Reputation: 21
I'm practicing sml using problems from Ullman(M97) second edition. The problem I am currently working on calls for a piglatin function that takes in a word, explodes it, and checks if the first character is a vowel (a, e, i, o u). If it is a vowel, it implodes the character list back into a string and adds "yay" at the end. If the first character is not a vowel, the function then checks the rest of the characters until it comes across the first vowel. When it does, it places all characters that came before the first vowel at the end of the character list, implodes the new character list back into a string and adds "ay" to it.
For example:
- pl "able";
val it = "ableyay" : string
- pl "stripe";
val it = "ipestray" : string
fun isVowel (c::cs) =
if c = #"a" then true
else if c = #"e" then true
else if c = #"i" then true
else if c = #"o" then true
else if c = #"u" then true
else false
fun cycle nil = nil
| cycle (h :: hs) = hs @ [h]
fun aL (h::hs) =
if isVowel(h) = true
then h :: hs
else aL (cycle (h :: hs))
fun plx (x) =
if isVowel x = true
then (implode x) ^ "yay"
else implode (aL (x)) ^ "ay"
fun pl (x) = plx (explode x)
I have most of the problem done, but I am stuck on why my plx function gives me this:
Error: operator and operand don't agree [tycon mismatch]
operator domain: char list list
operand: char list
in expression: aL x uncaught exception Error
and I am not sure how to fix it.
Upvotes: 2
Views: 81
Reputation: 16135
You may find Exercism's SML track enjoyable then. There's even a Pig Latin exercise. :-)
It is quite common to explode, analyse and implode, but it isn't very efficient, and in some cases it isn't easier either. As molbdnilo pointed out, isVowel
should probably accept a char
as input instead of a char list
:
fun isVowel c =
c = #"a" orelse
c = #"e" orelse
c = #"i" orelse
c = #"o" orelse
c = #"u"
For the function that converts a word into pig latin, you can do this entirely with string functions:
fun piglatin (word : string) =
let val firstLetter = String.sub (word, 0)
in if isVowel firstLetter
then word ^ "yay"
else String.extract (word, 1, NONE) ^ str firstLetter ^ "ay"
end
Testing this:
- piglatin "pig";
> val it = "igpay" : string
- piglatin "ant";
> val it = "antyay" : string
Now, there are corner cases:
What if the word is the empty ""
?
- piglatin "";
! Uncaught exception:
! Subscript
What if the word is the uppercased "Ant"
?
- piglatin "Ant";
> val it = "ntAay" : string
Those two problems will need to be addressed to make the string-based piglatin
function robust and total.
Here is some feedback for the solution you posted:
if P then true else Q
; write P orelse Q
.isVowel c = true
; write isVowel c
.aL
and plx
aren't the best function names; I'm not sure exactly what they're supposed to except act as glue between pl
and cycle
, isVowel
, explode
and implode
.Upvotes: 0
Reputation: 66459
It's because the type of isVowel
is char list -> bool
.
If you look at aL
:
fun aL (h::hs) = if isVowel(h) = true then h :: hs
else aL (cycle (h :: hs));
the isVowel(h)
means that h
must be a char list
, and this in turn means that aL
must have type char list list -> char list list
, and implode (aL x)
is an error.
To fix, change isVowel
to char -> bool
:
fun isVowel c = ...
and write isVowel (hd x)
in plx
.
Upvotes: 1