views:

122

answers:

3

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

+3  A: 
  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"].

Dave Hinton
thanks, i understand now :-).
moshe
great again, i understand you very well :-).thanks a lot for this :-).
moshe
http://www.haskell.org/ghc/docs/latest/html/users_guide/syntax-extns.html#pattern-guards The language extension `{-# LANGUAGE PatternGuards #-}` lets you pattern match within guards.
ephemient
+2  A: 

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.

Thiago Arrais
1. i did lists == [] = [] and put the type definition, but it raised an error.maybe it because the eq code(i don't understand right now).2. i don't understand what is the difference between the fix you suggested to me and the first example of your code(that works great also with the type definition).you just used case of and i use guards, so why i get the error, and in your example everythings works great?3. what do you mean by idiomatically?i'm not very fluent with english, plaese explain :-).
moshe
see here:http://stackoverflow.com/questions/2057093/exercise-on-haskell-type-definition-and-guards/2057352#2057352
moshe
By idiomatically, I mean in a more Haskellish style: the way Haskell people write Haskell. You can write COBOL in any language, you know? But when I'm learning a new language, I like to learn how the more experienced practitioners (native speakers, if you like) use it, not just what the compiler would understand.
Thiago Arrais
The difference between the fix and the first example is, as you correctly noticed, that the example uses pattern matching (the `case of` expression) and you original code uses guards. The guard expression needs to be evaluated to a single Bool value and that's what you accomplish by using the equals operator. It's just a regular operator that could be used anywhere in the function body, you just happened to use it in the guard clause. As such it needs two fully-defined values to work, you can't match patterns within it. Inside the case expression, however, you can (and should) pattern-match.
Thiago Arrais
By the way, if you change the guard in your code to `length lists == 0`, the code will also type check. The equals operator in Haskell is something provided by the `Eq` type class, the only things that can be compared for equality are types of it. When you used equals to compare your entry to the empty list, you just tied your code to the `Eq` class. By using length, what you're comparing for equality is the integer returned by the function with the integer 0, not the list itself. You could also achieve the same effect by using `null` (check its type signature and you'll understand why).
Thiago Arrais
thanks for your comments, can you please see this?:http://stackoverflow.com/questions/2057093/exercise-on-haskell-type-definition-and-guards/2057352#2057352
moshe
thanks a lot for the other examples and explanations :-)
moshe
A: 

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.

moshe
If you changed the guard clause in the function from the question to `length lists == 0`, and did not change the resulting empty *string* to an empty *list*, you'll still get a type error. Your empty list case will return a string and this will force the generic type `a` to be changed to the concrete type `[Char]` (or `String`). By changing the guard clause you just get rid of the `Eq` type class, but if you don't change the return value the function signature will require the more specific type `[Char]`.
Thiago Arrais
thanks for that :-)
moshe