开发者

Using Either correctly

So I have the following function:

chk2 :: [(Integer,Integer)] -> Either [(Integer,Integer)] (Integer,Integer)
chk2 i@((n,_):_)
  | chkp (prod $ lgst i)==True = Right $ lgst i
  | lgst i=开发者_开发技巧=i!!0 = Left $ chk2 $ (4-2,4-2):next i                                           
  | otherwise = Left $ chk2 $ next i
  where prod (a,b) = a*b
        lgst = foldl1 (\(a,b) (c,d) -> if prod (a,b) > prod (c,d) then (a,b) else (c,d))
        next t = map (\(a,b) -> if (a,b)==lgst t then (a-1,b+1) else (a,b)) t

along with this error:

runhugs: Error occurred
ERROR "4/4.hs":14 - Type error in explicitly typed binding
*** Term           : chk2
*** Type           : [(Integer,Integer)] -> Either (Either [(Integer,Integer (Integer,Integer)) (Integer,Integer)
*** Does not match : [(Integer,Integer)] -> Either [(Integer,Integer)] (Integer,Integer)

I'm trying to get this function to either end up with an (a,b) i.e. first guard or [(a,b)] i.e. the latter two guards. The basic problem is in the latter two guards.. if I take out the recursion, everything works fine, but I'm not sure how to define the type signature when returning the function itself.


The problem is with how you recurse.

According to the type of chk2, chk2 $ next i is of type Either [(Integer,Integer)] (Integer,Integer). Left is of type b -> Either b a, so Left $ chk2 $ next i is of type Either (Either [(Integer,Integer)] (Integer,Integer)) a for some unspecified type a.

Left $ chk2 $ (4-2,4-2):next i has a similar problem.

To fix, you need to decide how you want to handle the recursive value.

Easy fix:

  | lgst i==i!!0 = chk2 $ (4-2,4-2):next i                                           
  | otherwise = chk2 $ next i

However, I doubt this is what you want, since it means all your results will be Right. I'm not sure how to do what you want, because I'm not sure what you want.

What does a list result mean? What does a non-list result mean?

What you probably want to do is pattern match the result of the recursion, transforming Right pair -> Left [pair], perhaps appending some other result to the front.

As an example, I'll construct a recursive function with a similar type signature. Let foo be a function that takes a list of integers, and:

  • if the first element of the list is the maximum of the whole list, returns that element
  • otherwise, return a subsequence of the list, where each is the maximum of all the elements between it and the next element in the subsequence (or the end)

To do this:

foo :: [Integer] -> Either [Integer] Integer
foo [] = Left []
foo (x:xs) = case foo xs of
  Left ys -> if all (<=x) ys
              then Right x
              else let (_,ys') = break (>x) ys in Left (x:ys')
  Right y -> if x >= y
              then Right x
              else Left [x,y]

Note how I use case to pattern match on the result of the recursive call to foo.


To solve Euler #4, yours seems to be a very awkward style for Haskell. It's usually a bad idea to try and "port" code from other languages into Haskell, since the paradigm for Haskell is so very different.

You'll find a very clean, sensible solution to Euler #4 that uses list comprehensions at the Haskell Wiki. Certainly not the only solution, but it is at least 20x as readable as your current code. No offense.

I (and tons of other Haskellers) highly recommend Learn You a Haskell and Real World Haskell for learning how to approach problems the Haskell way, which in my experience is usually to create small, simple helper methods and compose them into a solution.

0

上一篇:

下一篇:

精彩评论

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

最新问答

问答排行榜