Re: [Haskell-beginners] Are these soloutions all valid and a good use of Haskell

I try to say that if the input list has only 1 item the outcome is the head of that list.
This is not how one typically thinks about folds. Look at the type of acc: acc :: a -> Maybe a -> Maybe a acc is a function wich takes two arguments (ignoring currying): On is of type `a`. This is the element type of the list you fold over. The other is of type `Maybe a`. This is the value you accumulate in your fold. The initial value is `Nothing`. You start your fold literally with nothing, since you haven't visited any element in the list yet. Now the first element of the list (see below) is passed to acc. What do you do with it? acc a Nothing = ??? a is an element in your lit, Nothing is the value you have accumulated so far. What do you do? Ignore a? Keep it? If you ignore a, you return `Nothing`. acc a Nothing = Nothing With this accumulator, the list will be traversed (ignoring lazy evaluation for the time being), all values will be ignored and your result will be Nothing, no matter what kind of list you fold over. Therefore, let's keep value `a`. In order to do that, we have to wrap it in a Just, otherwise the types won't match: acc a Nothing = Just a This function will give the right result for empty lists (Nothing) and for lists with a single value where the value is wrapped in a Just. The function will throw an error however, if you pass it a list containing more than one element, because the pattern match is not exhaustive. We need to decide what happens, when we already have a value wrapped in a Just: acc a Just b = ??? Here you have three possibilities. a) return Just b, b) return Just a, c) return Nothing. These are all the options you have. Anything else (except for throwing errors) will not compile. You can try each of the three. One will give you the head of the list, one will give you the last item of the list, and one will give you Nothing for lists with more than one element. Note that the result of your function depends on which fold you use. foldl folds from the left. The first element passed to the accumulating function will be the head of the list. foldr folds from the right. The first value passed to the accumulating function is the last in the list. So, think about the fold like this: Every element of the list is passed to your accumulator and each time you must decide whether you want to keep it or let it pass. If you keep them all, you will in the end hold the last element passed to your accumulator. If you let them all pass (except for the first, which you keep since you still have Nothing), you will end up with the first element passed to you. If you fold from the right, the first element you get is the last in the list. Keep it and don't let it go. If you fold from the left, the first element will be the head of the list. Throw them all away except for the very last one. Feel free to ask, if this doesn't make sense. Stefan
Stefan Höck schreef op 10-11-2014 15:23:
Just a quick note: That's 'typed holes' not 'type holes' ...
On Mon, Nov 10, 2014 at 03:12:20PM +0100, Stefan Höck wrote:
Hi Roelof
It seems like you try to do too many things at once. Here's how you could go about this step-by-step and let GHC help you implement your functions along the way:
First, give the type signature of your function:
last5 :: [a] -> Maybe a last5 = undefined
Now, load this into GHCi or compile with GHC. If it compiles, you're on the right track. Now, you want to implement it using a fold (try both, foldl and foldr):
last5 :: [a] -> Maybe a last5 xs = foldr _ _ xs
The underscores are 'type holes'. This tells the compiler to give you some information about what is supposed to be placed at the two positions. For the moment, we are only interested in the types of the things that go there. The compiler will tell you, that the hole at the first position is of type
a -> Maybe a -> Maybe a
and the hole at the second position is of type
Maybe a
Now, instead of filling the holes in place, let's define two helper functions together with their type signatures. You can later on inline them in your definition of last5, but for the time being, let's get as much help from the compiler as we can.
last5 :: [a] -> Maybe a last5 xs = foldr acc initial xs
acc :: a -> Maybe a -> Maybe a acc = undefined
initial :: Maybe a initial = undefined
Again, compile or load into GHCi. If you did anything wrong, the compiler will tell you so. There is only one possible way to implement function `initial` without cheating (= raising an error)
initial :: Maybe a initial = Nothing
Function `acc` can be implemented in several ways. Only one of them will lead to the desired behavior. Finding out the proper implementation is the main point of this folding-exercise. Try also an implementation using foldl. Does it behave as expected? What are the differences compared to foldr? When you feed your implementations a huge list - say [1..20000000] - what happens?
Note that whenever you get an error message in a rather complex function implementation, move local function definitions and lambdas to the top level, give them a type signature and implement them separately one at a time. Use type holes to let the compiler give assistance with type signatures and possible implementations. Once everything compiles and runs as expected, move the toplevel definitions back to where you'd like them best.
Stefan
PS: A more succint implementation of last5 would use currying:
last5 = foldr acc initial
PPS: If you get a stack overflow with very large lists, try using foldl' from Data.List (or better, once you learned about the Foldable type class, from Data.Foldable).
On Mon, Nov 10, 2014 at 02:28:08PM +0100, Roelof Wobben wrote:
I tried and so far I have this :
last5 = foldl(\acc x -> if x=[] then x else acc xs) [] xs
But now I get parse error on the -> part.
Roelof
Roelof Wobben schreef op 10-11-2014 13:47:
Thanks all,
I will try to make a fold solution as soon as I see that functional explained in the learnyouahaskell.
Roelof
Frerich Raabe schreef op 10-11-2014 11:43:
On 2014-11-10 11:16, Karl Voelker wrote: >On Mon, Nov 10, 2014, at 01:50 AM, Roelof Wobben wrote: >>What do you experts think of the different ways ? >2 and 4 are quite similar, and both fine. 3 is not so good: guards >provide weaker guarantees than patterns, and head and tail are partial >functions. In addition to what Karl wrote, I'd like to suggest not using the semicolon all the time -- it's not needed and just adds noise.
>All three implementations have in common that they do their own >recursion. It would be a good exercise to try implementing last as a >fold - in other words, letting the standard library do the recursion >for >you. Right - I suggest trying to express the problem with the most abstract function first, then consider using a fold, then use manual recursion. in your particular case you could exploit that for non-empty lists, getting the last element of a list is the same as getting the first element of a reversed list (and there are ready-made functions for reversing a list and getting the first element of a list).
_______________________________________________ Beginners mailing list Beginners@haskell.org http://www.haskell.org/mailman/listinfo/beginners
_______________________________________________ Beginners mailing list Beginners@haskell.org http://www.haskell.org/mailman/listinfo/beginners
Beginners mailing list Beginners@haskell.org http://www.haskell.org/mailman/listinfo/beginners

Stefan Höck schreef op 10-11-2014 17:18:
I try to say that if the input list has only 1 item the outcome is the head of that list. This is not how one typically thinks about folds. Look at the type of acc:
acc :: a -> Maybe a -> Maybe a
acc is a function wich takes two arguments (ignoring currying): On is of type `a`. This is the element type of the list you fold over. The other is of type `Maybe a`. This is the value you accumulate in your fold. The initial value is `Nothing`. You start your fold literally with nothing, since you haven't visited any element in the list yet. Now the first element of the list (see below) is passed to acc. What do you do with it?
acc a Nothing = ???
a is an element in your lit, Nothing is the value you have accumulated so far. What do you do? Ignore a? Keep it? If you ignore a, you return `Nothing`.
acc a Nothing = Nothing
With this accumulator, the list will be traversed (ignoring lazy evaluation for the time being), all values will be ignored and your result will be Nothing, no matter what kind of list you fold over. Therefore, let's keep value `a`. In order to do that, we have to wrap it in a Just, otherwise the types won't match:
acc a Nothing = Just a
This function will give the right result for empty lists (Nothing) and for lists with a single value where the value is wrapped in a Just. The function will throw an error however, if you pass it a list containing more than one element, because the pattern match is not exhaustive. We need to decide what happens, when we already have a value wrapped in a Just:
acc a Just b = ???
It makes sence except when I enter acc a Just B I see this error message : ConstructorJustshould have 1 argument, but has been given none…

This is simply a precedence problem. Judicious use of parentheses will
solve it.
On Mon Nov 10 2014 at 16:32:36 Roelof Wobben
I try to say that if the input list has only 1 item the outcome is the
Stefan Höck schreef op 10-11-2014 17:18: head
of that list. This is not how one typically thinks about folds. Look at the type of acc:
acc :: a -> Maybe a -> Maybe a
acc is a function wich takes two arguments (ignoring currying): On is of type `a`. This is the element type of the list you fold over. The other is of type `Maybe a`. This is the value you accumulate in your fold. The initial value is `Nothing`. You start your fold literally with nothing, since you haven't visited any element in the list yet. Now the first element of the list (see below) is passed to acc. What do you do with it?
acc a Nothing = ???
a is an element in your lit, Nothing is the value you have accumulated so far. What do you do? Ignore a? Keep it? If you ignore a, you return `Nothing`.
acc a Nothing = Nothing
With this accumulator, the list will be traversed (ignoring lazy evaluation for the time being), all values will be ignored and your result will be Nothing, no matter what kind of list you fold over. Therefore, let's keep value `a`. In order to do that, we have to wrap it in a Just, otherwise the types won't match:
acc a Nothing = Just a
This function will give the right result for empty lists (Nothing) and for lists with a single value where the value is wrapped in a Just. The function will throw an error however, if you pass it a list containing more than one element, because the pattern match is not exhaustive. We need to decide what happens, when we already have a value wrapped in a Just:
acc a Just b = ???
It makes sence except when I enter acc a Just B I see this error message : ConstructorJustshould have 1 argument, but has been given none… _______________________________________________ Beginners mailing list Beginners@haskell.org http://www.haskell.org/mailman/listinfo/beginners

It is complining but as soon as I want to run it , I see this message :
Non-exhaustive patterns in function acc
Yep, Maybe has two constructors, and you are only handling one. You should handle the Nothing case as well.

Let's do this step by step. We use the following list: [1,2,3] foldr takes three arguments: foldr :: (a -> b -> b) -> b -> [a] -> b The last of the three has type [a]. This means, the fold expects a list as an argument here. The lower case letter `a` is the type of the items in the list. In our case this is `Int`, but we could pass it other lists with other element types. The second argument of the fold has type `b`, this is the result type we'd like to get from the fold. In our case this is `Maybe Int` since we want to know from the result, whether the list was empty or not. Nothing in case of an empty list, Just x with x being the right-most item in the non-empty case. The first argument of the fold is a higher order function. It accepts an argument of type `a` (the element type of the list) and of type `b` (the result type of the fold) and should return a value of type `b`. In our example, `a` is equal to `Int` and b is equal to `Maybe Int`. Therefore, the following cannot possibly work:
acc a acc = if null a then Nothing else if (null (tail a)) then (Just
the first argument of acc (the value `a` in your implementation) has type `a` (note the distinction between a value and a type, both have the same name here, but that doesn't need to be the case. You could rename the value to x or foo or whatever). In our case, the type `a` is `Int` since we fold over a list of Ints. If we were to fold over a list of Strings, type `a` would be equal to `String`. Note however, that since `a` can be anything (Int, String etc, depending on the element type of your list), you cannot possibly call `null` on it. null takes a list as an argument, but `a` is not necessarily a list. It's the type of the list's elements, not the whole list. You do not pass the whole list to the accumulator. You only pass it the list's element in single file. Now, what happens, when we fold over the list? Since we fold from the right, our accumulator is passed two arguments: The last value of the list and the initial value of type `b` (in our case `Nothing`). acc 3 Nothing = ??? What should be the result of this? Clearly you'd like to keep the 3 as it is actually the result you are looking for. But you cannot return the 3 directly. The return type of our function must be `Maybe Int` and the type of `3` is `Int`. We first must wrap the `3` in a `Maybe`. There is only one way to do that: acc 3 Nothing = Maybe 3 (This is pseudocode an will not compile. The real implementation follows below) Now comes the next item in the list: `2`. Function acc gets called again, this time with `2` as its first argument, and the result of our fold so far which is `Just 3` acc 2 (Just 3) = ??? Clearly we do not want to lose the `3`, it's the result we are looking for after all! acc 2 (Just 3) = Just 3 Finally, the last item (from the right) in the list comes along: acc 1 (Just 3) = Just 3 Again we let it pass and get Just 3 as the result. This is how foldr works. Every element of the list starting with the rightmost is passed as an argument to the accumulator function together with the value accumulated so far (for which you must provide an initial value). Now, the implementation. We have seen, that we want to get hold of the very first value that comes from the list and ignore everything else that comes after it. acc :: a -> Maybe a -> Maybe a # This is the function's type signature acc x Nothing = Just x # We wrap the first value ... acc x (Just y) = Just y # and keep hold of it When we now use this accumulator in our fold, it gets first called with arguments `3` and `Nothing` so the first pattern matches. Variable x is assigned the value `3` and the result is `Just 3`. The function gets called again with the second value `2` and `Just 3`, the result from the first call. This time, the first pattern does not match (Nothing does not match `Just 3`), but the second does. `x` is assigned the value `2`, `y` is assigned the value `3` (the one wrapped in the `Just`) and the result is `Just 3`. Same for the last element. Here is the complete implementation: last5 :: [a] -> Maybe a last5 = foldr acc Nothing where acc x Nothing = Just x acc x (Just y) = Just y Or better last5 :: [a] -> Maybe a last5 = foldr acc Nothing where acc x Nothing = Just x acc _ j = j Or even (this one will be harder to figure out) last5 :: [a] -> Maybe a last5 = foldr acc Nothing where acc x = maybe (Just x) Just Cheers, Stefan On Mon, Nov 10, 2014 at 06:28:46PM +0100, Roelof Wobben wrote:
oke, I try it with this : acc :: a -> Maybe a -> Maybe a acc a acc = if null a then Nothing else if (null (tail a)) then (Just acc) else acc a acc else if the tail a is empty so there is only 1 item then the output must be acc else must be run again ( there is a list with more then 1 item) but now I see this error message : Couldn't match expected type ‘a -> Maybe a -> Maybe a’ with actual type ‘Maybe a’ Relevant bindings include acc :: Maybe a and that is on the else part Roelof Benjamin Edwards schreef op 10-11-2014 18:07:
It is complining but as soon as I want to run it , I see this message : Non-exhaustive patterns in function acc
Yep, Maybe has two constructors, and you are only handling one. You should handle the Nothing case as well.
_______________________________________________ Beginners mailing list [1]Beginners@haskell.org [2]http://www.haskell.org/mailman/listinfo/beginners
References
1. mailto:Beginners@haskell.org 2. http://www.haskell.org/mailman/listinfo/beginners
_______________________________________________ Beginners mailing list Beginners@haskell.org http://www.haskell.org/mailman/listinfo/beginners

Stefan Höck schreef op 10-11-2014 20:47:
Let's do this step by step. We use the following list: [1,2,3]
foldr takes three arguments:
foldr :: (a -> b -> b) -> b -> [a] -> b
The last of the three has type [a]. This means, the fold expects a list as an argument here. The lower case letter `a` is the type of the items in the list. In our case this is `Int`, but we could pass it other lists with other element types.
The second argument of the fold has type `b`, this is the result type we'd like to get from the fold. In our case this is `Maybe Int` since we want to know from the result, whether the list was empty or not. Nothing in case of an empty list, Just x with x being the right-most item in the non-empty case.
The first argument of the fold is a higher order function. It accepts an argument of type `a` (the element type of the list) and of type `b` (the result type of the fold) and should return a value of type `b`. In our example, `a` is equal to `Int` and b is equal to `Maybe Int`.
Therefore, the following cannot possibly work:
acc a acc = if null a then Nothing else if (null (tail a)) then (Just
the first argument of acc (the value `a` in your implementation) has type `a` (note the distinction between a value and a type, both have the same name here, but that doesn't need to be the case. You could rename the value to x or foo or whatever). In our case, the type `a` is `Int` since we fold over a list of Ints. If we were to fold over a list of Strings, type `a` would be equal to `String`. Note however, that since `a` can be anything (Int, String etc, depending on the element type of your list), you cannot possibly call `null` on it. null takes a list as an argument, but `a` is not necessarily a list. It's the type of the list's elements, not the whole list. You do not pass the whole list to the accumulator. You only pass it the list's element in single file.
Now, what happens, when we fold over the list? Since we fold from the right, our accumulator is passed two arguments: The last value of the list and the initial value of type `b` (in our case `Nothing`).
acc 3 Nothing = ???
What should be the result of this? Clearly you'd like to keep the 3 as it is actually the result you are looking for. But you cannot return the 3 directly. The return type of our function must be `Maybe Int` and the type of `3` is `Int`. We first must wrap the `3` in a `Maybe`. There is only one way to do that:
acc 3 Nothing = Maybe 3
(This is pseudocode an will not compile. The real implementation follows below)
Now comes the next item in the list: `2`. Function acc gets called again, this time with `2` as its first argument, and the result of our fold so far which is `Just 3`
acc 2 (Just 3) = ???
Clearly we do not want to lose the `3`, it's the result we are looking for after all!
acc 2 (Just 3) = Just 3
Finally, the last item (from the right) in the list comes along:
acc 1 (Just 3) = Just 3
Again we let it pass and get Just 3 as the result.
This is how foldr works. Every element of the list starting with the rightmost is passed as an argument to the accumulator function together with the value accumulated so far (for which you must provide an initial value).
Now, the implementation. We have seen, that we want to get hold of the very first value that comes from the list and ignore everything else that comes after it.
acc :: a -> Maybe a -> Maybe a # This is the function's type signature acc x Nothing = Just x # We wrap the first value ... acc x (Just y) = Just y # and keep hold of it
When we now use this accumulator in our fold, it gets first called with arguments `3` and `Nothing` so the first pattern matches. Variable x is assigned the value `3` and the result is `Just 3`.
The function gets called again with the second value `2` and `Just 3`, the result from the first call. This time, the first pattern does not match (Nothing does not match `Just 3`), but the second does. `x` is assigned the value `2`, `y` is assigned the value `3` (the one wrapped in the `Just`) and the result is `Just 3`. Same for the last element.
Here is the complete implementation:
last5 :: [a] -> Maybe a last5 = foldr acc Nothing where acc x Nothing = Just x acc x (Just y) = Just y
Or better
last5 :: [a] -> Maybe a last5 = foldr acc Nothing where acc x Nothing = Just x acc _ j = j
Or even (this one will be harder to figure out) last5 :: [a] -> Maybe a last5 = foldr acc Nothing where acc x = maybe (Just x) Just
Cheers, Stefan
I understand the theory but i loose it on the implementation. Lets take the better variant. last5 :: [a] -> Maybe a last5 = foldr acc Nothing where acc x Nothing = Just x acc _ j = j Let's say we have [1,2,3] Do I understand that acc = Nothing. and x = 3 ? and after acc x Nothing = Just x acc get's the value 3 But how does x get's the value 3 or does foldr takes care of that ? Roelof

I understand the theory but i loose it on the implementation.
Lets take the better variant.
last5 :: [a] -> Maybe a last5 = foldr acc Nothing where acc x Nothing = Just x acc _ j = j
Let's say we have [1,2,3]
Do I understand that acc = Nothing. and x = 3 ?
Not, acc is not Nothing. acc is a function of type (a -> Maybe a -> Maybe a). Nothing is a value of type Maybe a. The two cannot possibly be the same. foldr takes care of feeding the proper arguments to `acc`.
and after acc x Nothing = Just x acc get's the value 3
The result of calling `acc` with arguments 3 and Nothing is `Just 3`. But that's NOT the value of `acc`. acc is still a function. Note that there is no such thing as in-place mutation in Haskell, so you cannot just change the value of `acc`. But the RESULT of calling acc 3 Nothing is `Just 3`. This result is taken by foldr and passed again to `acc` together with the next item in the list. This continues until the list is exhausted and foldr returns the last result it got from calling `acc`.
But how does x get's the value 3 or does foldr takes care of that ?
foldr takes care of all that. foldr calls `acc` with the proper arguments and does all the bookkeeping internally. There is actually not much to bookkeep. Here's an implementation of foldr foldr :: (a -> b -> b) -> b -> [a] -> b foldr _ b [] = b foldr f b (a:as) = foldr f (f a b) as So, no great bookkeeping, just plain recursion. Stefan

Thanks, I think my error in thinking is that most of the languages store values in a variable, But it seems that haskell do not use it in a fold Roelof Stefan Höck schreef op 10-11-2014 21:15:
I understand the theory but i loose it on the implementation.
Lets take the better variant.
last5 :: [a] -> Maybe a last5 = foldr acc Nothing where acc x Nothing = Just x acc _ j = j
Let's say we have [1,2,3]
Do I understand that acc = Nothing. and x = 3 ? Not, acc is not Nothing. acc is a function of type (a -> Maybe a -> Maybe a). Nothing is a value of type Maybe a. The two cannot possibly be the same. foldr takes care of feeding the proper arguments to `acc`.
and after acc x Nothing = Just x acc get's the value 3 The result of calling `acc` with arguments 3 and Nothing is `Just 3`. But that's NOT the value of `acc`. acc is still a function. Note that there is no such thing as in-place mutation in Haskell, so you cannot just change the value of `acc`. But the RESULT of calling
acc 3 Nothing
is `Just 3`. This result is taken by foldr and passed again to `acc` together with the next item in the list. This continues until the list is exhausted and foldr returns the last result it got from calling `acc`.
But how does x get's the value 3 or does foldr takes care of that ? foldr takes care of all that. foldr calls `acc` with the proper arguments and does all the bookkeeping internally. There is actually not much to bookkeep. Here's an implementation of foldr
foldr :: (a -> b -> b) -> b -> [a] -> b foldr _ b [] = b foldr f b (a:as) = foldr f (f a b) as
So, no great bookkeeping, just plain recursion.
Stefan _______________________________________________ Beginners mailing list Beginners@haskell.org http://www.haskell.org/mailman/listinfo/beginners

Roelof Wobben schreef op 10-11-2014 20:59:
last5 :: [a] -> Maybe a last5 = foldr acc Nothing where acc x Nothing = Just x acc _ j = j
When I enter this in GHCI I see this error : Illegal type signature: ‘[a] -> Maybe a last5’

It's an indentation issue. Make sure that there are no spaces before the
bit about 'last5 = foldr acc' etc.
On Mon, Nov 10, 2014 at 12:48 PM, Roelof Wobben
Roelof Wobben schreef op 10-11-2014 20:59:
last5 :: [a] -> Maybe a last5 = foldr acc Nothing where acc x Nothing = Just x acc _ j = j
When I enter this in GHCI I see this error :
Illegal type signature: ‘[a] -> Maybe a last5’
_______________________________________________ Beginners mailing list Beginners@haskell.org http://www.haskell.org/mailman/listinfo/beginners

_ just means "ignore this parameter, I'm not going to use it"
On Tuesday, November 11, 2014, Roelof Wobben
Thanks, this is working well.
But just for understanding
in the part acc x Nothing x is the input string, and in the part _j means the same as (xs:x)
Roelof
Alex Hammel schreef op 10-11-2014 22:47:
It's an indentation issue. Make sure that there are no spaces before the bit about 'last5 = foldr acc' etc.
On Mon, Nov 10, 2014 at 12:48 PM, Roelof Wobben
javascript:_e(%7B%7D,'cvml','r.wobben@home.nl');> wrote: Roelof Wobben schreef op 10-11-2014 20:59:
last5 :: [a] -> Maybe a last5 = foldr acc Nothing where acc x Nothing = Just x acc _ j = j
When I enter this in GHCI I see this error :
Illegal type signature: ‘[a] -> Maybe a last5’
_______________________________________________ Beginners mailing list Beginners@haskell.org javascript:_e(%7B%7D,'cvml','Beginners@haskell.org'); http://www.haskell.org/mailman/listinfo/beginners
_______________________________________________ Beginners mailing listBeginners@haskell.org javascript:_e(%7B%7D,'cvml','Beginners@haskell.org');http://www.haskell.org/mailman/listinfo/beginners
-- Sent from an iPhone, please excuse brevity and typos.

The program traverses the list from right to left. The first element that
acc sees during traversal is the last element of the list.
The idea is as follows:
Parameter y is the partial calcresult.
If y (in your code) is Nothing then acc returns Just x. So the new partial
result is the current list element in a Just.
The next time acc is called, y is not Nothing but a Just. In that case acc
returns the partial calcresult unchanged.
So, y is Nothing for the last list element and Just <last element of the
list> for all other list elements.
last5 :: [a] -> Maybe a
last5 xs = foldr acc initial xs
acc :: a -> Maybe a -> Maybe a
acc x Nothing = Just x
acc _ aJust = aJust
initial :: Maybe a
initial = Nothing
In your code you dont need the where in the acc definition. Define acc
for Nothing and for Just.
Kees
---------------
Im now trying to make a rfold solution to this problem.
Till now I have this :
last5 :: [a] -> Maybe a
last5 xs = foldr acc initial xs
acc :: a -> Maybe a -> Maybe a
acc x y = where
acc x Nothing = Just x
acc _ j = j
initial :: Maybe a
initial = Nothing
So still not working.
Can someone explain to me in small steps how to figure out what the right
answer is to the acc part.
Roelof
Roelof Wobben schreef op 11-11-2014 8:20:
Thanks, this is working well.
But just for understanding
in the part acc x Nothing x is the input string,
and in the part _j means the same as (xs:x)
Roelof
Alex Hammel schreef op 10-11-2014 22:47:
It's an indentation issue. Make sure that there are no spaces before the bit
about 'last5 = foldr acc' etc.
On Mon, Nov 10, 2014 at 12:48 PM, Roelof Wobben

Another noob here.
Thanks for this step by step guide. Your writing style is very attractive.
Do you have blog about Haskell or any programming subject ?
Thanks.
2014. 11. 11. 오전 1:19에 "Stefan Höck"
I try to say that if the input list has only 1 item the outcome is the head of that list.
This is not how one typically thinks about folds. Look at the type of acc:
acc :: a -> Maybe a -> Maybe a
acc is a function wich takes two arguments (ignoring currying): On is of type `a`. This is the element type of the list you fold over. The other is of type `Maybe a`. This is the value you accumulate in your fold. The initial value is `Nothing`. You start your fold literally with nothing, since you haven't visited any element in the list yet. Now the first element of the list (see below) is passed to acc. What do you do with it?
acc a Nothing = ???
a is an element in your lit, Nothing is the value you have accumulated so far. What do you do? Ignore a? Keep it? If you ignore a, you return `Nothing`.
acc a Nothing = Nothing
With this accumulator, the list will be traversed (ignoring lazy evaluation for the time being), all values will be ignored and your result will be Nothing, no matter what kind of list you fold over. Therefore, let's keep value `a`. In order to do that, we have to wrap it in a Just, otherwise the types won't match:
acc a Nothing = Just a
This function will give the right result for empty lists (Nothing) and for lists with a single value where the value is wrapped in a Just. The function will throw an error however, if you pass it a list containing more than one element, because the pattern match is not exhaustive. We need to decide what happens, when we already have a value wrapped in a Just:
acc a Just b = ???
Here you have three possibilities. a) return Just b, b) return Just a, c) return Nothing. These are all the options you have. Anything else (except for throwing errors) will not compile. You can try each of the three. One will give you the head of the list, one will give you the last item of the list, and one will give you Nothing for lists with more than one element.
Note that the result of your function depends on which fold you use. foldl folds from the left. The first element passed to the accumulating function will be the head of the list. foldr folds from the right. The first value passed to the accumulating function is the last in the list.
So, think about the fold like this: Every element of the list is passed to your accumulator and each time you must decide whether you want to keep it or let it pass. If you keep them all, you will in the end hold the last element passed to your accumulator. If you let them all pass (except for the first, which you keep since you still have Nothing), you will end up with the first element passed to you. If you fold from the right, the first element you get is the last in the list. Keep it and don't let it go. If you fold from the left, the first element will be the head of the list. Throw them all away except for the very last one.
Feel free to ask, if this doesn't make sense.
Stefan
Just a quick note: That's 'typed holes' not 'type holes' ...
On Mon, Nov 10, 2014 at 03:12:20PM +0100, Stefan Höck wrote:
Hi Roelof
It seems like you try to do too many things at once. Here's how you could go about this step-by-step and let GHC help you implement your functions along the way:
First, give the type signature of your function:
last5 :: [a] -> Maybe a last5 = undefined
Now, load this into GHCi or compile with GHC. If it compiles, you're on the right track. Now, you want to implement it using a fold (try both, foldl and foldr):
last5 :: [a] -> Maybe a last5 xs = foldr _ _ xs
The underscores are 'type holes'. This tells the compiler to give you some information about what is supposed to be placed at the two positions. For the moment, we are only interested in the types of the things that go there. The compiler will tell you, that the hole at the first position is of type
a -> Maybe a -> Maybe a
and the hole at the second position is of type
Maybe a
Now, instead of filling the holes in place, let's define two helper functions together with their type signatures. You can later on inline them in your definition of last5, but for the time being, let's get as much help from the compiler as we can.
last5 :: [a] -> Maybe a last5 xs = foldr acc initial xs
acc :: a -> Maybe a -> Maybe a acc = undefined
initial :: Maybe a initial = undefined
Again, compile or load into GHCi. If you did anything wrong, the compiler will tell you so. There is only one possible way to implement function `initial` without cheating (= raising an error)
initial :: Maybe a initial = Nothing
Function `acc` can be implemented in several ways. Only one of them will lead to the desired behavior. Finding out the proper implementation is the main point of this folding-exercise. Try also an implementation using foldl. Does it behave as expected? What are the differences compared to foldr? When you feed your implementations a huge list - say [1..20000000] - what happens?
Note that whenever you get an error message in a rather complex function implementation, move local function definitions and lambdas to the top level, give them a type signature and implement them separately one at a time. Use type holes to let the compiler give assistance with type signatures and possible implementations. Once everything compiles and runs as expected, move the toplevel definitions back to where you'd like them best.
Stefan
PS: A more succint implementation of last5 would use currying:
last5 = foldr acc initial
PPS: If you get a stack overflow with very large lists, try using foldl' from Data.List (or better, once you learned about the Foldable type class, from Data.Foldable).
On Mon, Nov 10, 2014 at 02:28:08PM +0100, Roelof Wobben wrote:
I tried and so far I have this :
last5 = foldl(\acc x -> if x=[] then x else acc xs) [] xs
But now I get parse error on the -> part.
Roelof
Roelof Wobben schreef op 10-11-2014 13:47:
Thanks all,
I will try to make a fold solution as soon as I see that functional explained in the learnyouahaskell.
Roelof
Frerich Raabe schreef op 10-11-2014 11:43: >On 2014-11-10 11:16, Karl Voelker wrote: >>On Mon, Nov 10, 2014, at 01:50 AM, Roelof Wobben wrote: >>>What do you experts think of the different ways ? >>2 and 4 are quite similar, and both fine. 3 is not so good: guards >>provide weaker guarantees than patterns, and head and tail are
>>functions. >In addition to what Karl wrote, I'd like to suggest not using the >semicolon all the time -- it's not needed and just adds noise. > >>All three implementations have in common that they do their own >>recursion. It would be a good exercise to try implementing last as a >>fold - in other words, letting the standard library do the recursion >>for >>you. >Right - I suggest trying to express the problem with the most abstract >function first, then consider using a fold, then use manual recursion. >in >your particular case you could exploit that for non-empty lists, getting >the last element of a list is the same as getting the first element of >a reversed list (and there are ready-made functions for reversing a
Stefan Höck schreef op 10-11-2014 15:23: partial list
>and getting the first element of a list). > _______________________________________________ Beginners mailing list Beginners@haskell.org http://www.haskell.org/mailman/listinfo/beginners
_______________________________________________ Beginners mailing list Beginners@haskell.org http://www.haskell.org/mailman/listinfo/beginners
Beginners mailing list Beginners@haskell.org http://www.haskell.org/mailman/listinfo/beginners
_______________________________________________ Beginners mailing list Beginners@haskell.org http://www.haskell.org/mailman/listinfo/beginners

I used to have a blog (well I still do), but it was about functional reactive programming in Scala. I'm actually quite a noob in Haskell myself but with some experince in functional programming in Scala. There is a Scala library called 'scalaz' which was inspired by all the cool concepts found in Haskell and Cathegory Theory and I learned lots of stuff there. Nowadays, two little children keep me busy. No time for blogs. :-) On Tue, Nov 11, 2014 at 02:05:52AM +0900, Dontdie YCH wrote:
Another noob here.
Thanks for this step by step guide. Your writing style is very attractive.
Do you have blog about Haskell or any programming subject ?
Thanks.
participants (7)
-
Alex Hammel
-
Benjamin Edwards
-
Dontdie YCH
-
Julian Birch
-
Kees Bleijenberg
-
Roelof Wobben
-
Stefan Höck