exercise on haskell, type definition, and guards
first question:
Define a function that joins a list of lists together using a separator value. the type definition should be like that:intersperse :: a -> [[a]] -> [a]
The separator should appear between elements of the list, but should not follow the last element.
Your function should behave as follows:
ghci> :load Intersperse
[1 of 1] Compiling Main ( Intersperse.hs, interpreted )
Ok, modules loaded: Main.
ghci> intersperse ',' []
""
ghci> intersperse ',' ["foo"]
"foo"
ghci> intersperse ',' ["foo","bar","baz","quux"]
"foo,bar,baz,quux"
after some time i manage to solve it:
intersperse myChar lists
| lists == [] = ""
| otherwise = attach myChar lists
where attach myChar (x:[]) = x
attach myChar (x:xs) = x ++ (myChar : []) ++ attach myChar xs
but, as you see, it's without the type definition.
if i put the type definition above the function, i get an error. why?second question:
before i get to this solution, i want to put another guard in the list of guards. this quard should be after the first guard. i want to check if the lists variable has just one list in it, so i just return the lists variable. but i can't do a gua开发者_StackOverflow中文版rd like that(again, an error is come to life :-)):
| lists == (x:[]) = lists
and also this didn't work:
| lists == (_:[]) = lists
why why why ? :-).
after this i tried to make other guard:
| length lists == 1 = lists
but it also raised an error.
(by the way, i don't need those guards, because i found that the first pattern after the "where" keyword, is exactly what i want.
this is the pattern i mean: attach myChar (x:[]) = xbut still, i want to understand why the quards i tried, didn't work. also, i found this solution, by luck, and i don't think everytime i will notice such a things :-)
thanks a lot :-).
p.s. this exercise is from the book real world haskell.
""
is of type[Char]
, but your type signature saysintersperse
returns a[a]
, wherea
depends on the input type, so the types don't match.I don't think you can pattern match inside guards.
For this guard
| length lists == 1 = lists
lists
is of type[[a]]
, but you are supposed to be returning a[a]
. That is, iflists
is["foo"]
, you want to return"foo"
. You do not want to return["foo"]
.
The problem is that your function is not generalized, it will work only for Strings (lists of Char). If you change your second line to
lists == [] = []
you'll get what you want, although with a dependency to the Eq
type class due to the equals operator. It will even work for strings, because all strings are also lists, but not all lists are strings.
By the way, you may generalize your function even further by using pattern matching:
intersperse myChar lists = case lists of
[] -> []
lists -> attach myChar lists
where attach myChar (x:[]) = x
attach myChar (x:xs) = x ++ (myChar : []) ++ attach myChar xs
Or, more idiomatically:
intersperse _ [] = []
intersperse x xs = attach x xs
where attach myChar (x:[]) = x
attach myChar (x:xs) = x ++ (myChar : []) ++ attach myChar xs
And getting rid of the inner function:
intersperse _ [] = []
intersperse _ (xs:[]) = xs
intersperse x (xs:xss) = (xs ++ x:intersperse x xss)
Regarding the second question, the equals operator that you're using in the guards needs values in both sides. You can't pattern match with it. Maybe what you're looking for is something like the second refinement here.
this raise an error.
why?
it just the same as you did, besides you write it with case of
.
intersperse :: a -> [[a]] -> [a]
intersperse myChar lists
| lists == [] = []
| otherwise = attach myChar lists
where attach myChar (x:[]) = x
attach myChar (x:xs) = x ++ (myChar : []) ++ attach myChar xs
this don't raise an error(it's what you seggested):
intersperse :: a -> [[a]] -> [a]
intersperse myChar lists = case lists of
[] -> []
lists -> attach myChar lists
where attach myChar (x:[]) = x
attach myChar (x:xs) = x ++ (myChar : []) ++ attach myChar xs
but in my example(first function here), i changed the guard to what you suggested and still i get an error.
why is that?
thanks a lot.
it may be wrong, but it seems to work
intersperse :: a -> [[a]] -> [a]
intersperse _ [] = []
intersperse separator [xs] = xs
intersperse separator (x:xs) = x ++ [separator] ++ (intersperse separator xs)
精彩评论