开发者

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:[]) = x

but 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.


  1. "" is of type [Char], but your type signature says intersperse returns a [a], where a depends on the input type, so the types don't match.

  2. 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, if lists 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)
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜