问题
I am trying to wrap my head around the syntax of Haskell.
This problem is very simple to solve logically. I have to break up a list of positive and negative integers and group them such that
[1,2,3,-1,-2,-3,1,2,3] becomes [[1,2,3],[-1,-2,-3], [1,2,3]]
I would like to use a higher order function, foldr to be able to do that with an anonymous function taking in two arguements.
This is what I have so far.
split = foldr (\ x y -> if (x > 0)
then if (head (head y)) < 0
then [x] : y
else x : head y --error here
else if (x < 0)
then if (head (head y)) > 0
then [x] : y
else x : head y
else y
)
[[]]
this is the error i get
Occurs check: cannot construct the infinite type: a0 = [a0]
In the first argument of `(:)', namely `x'
In the expression: x : head y
In the expression:
if (head (head y)) < 0 then [x] : y else x : head y
I have two questions.
1) Why am I getting a type error at line 7?
Am I not concatenation an integer (x) to a list of integers (head y)
2) How do you write the conditions out using guards? I tried doing it but I kept getting parsing error at '|'
回答1:
You're simply missing to keep tail y
. In
foldr (\ x y -> if (x > 0)
then if (head (head y)) < 0
then [x] : y
else x : head y
you have x :: (Num a, Ord a) => a
, y :: (Num a, Ord a) => [[a]]
, and head y :: (Num a, Ord a) => [a]
.
So forgetting the tail y
shaves off one layer of []
. the else
branch should be
else (x:head y) : tail y
in both branches of the outer if
.
But, your function has two semantic problems after that.
First, you don't treat the case that head y
is empty, that will cause an exception when the end of the list is reached, and second, it doesn't work on infinite lists, since the combinator function doesn't construct anything of the result before its second argument is known. If the latter is a problem, you can find a sufficiently lazy combinator function in this answer.
回答2:
A function can have only one concrete return type and
[x] : y
is a different type fromx : head y
.It's probably easier to write it with
takeWhile
anddropWhile
:split l = split' (if head l > 0 then (>) else (<)) l where split' op [] = [] split' op l = takeWhile (`op` 0) l : split (dropWhile (`op` 0) l)
来源:https://stackoverflow.com/questions/12883559/guards-and-concatiating-to-lists-in-an-anonymous-function