正确使用Either

时间:2011-01-23 00:37:12

标签: haskell

所以我有以下功能:

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

以及此错误:

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)

我试图让这个功能最终得到(a,b)即第一后卫或 [(a,b)] ,即后者两名警卫。基本的问题是后两个警卫..如果我拿出递归,一切正常,但我不知道如何在返回函数本身时定义类型签名。

2 个答案:

答案 0 :(得分:3)

问题在于你如何递归。

根据chk2的类型,chk2 $ next i的类型为Either [(Integer,Integer)] (Integer,Integer)Left的类型为b -> Either b a,因此某些未指定类型Left $ chk2 $ next i的{​​{1}}类型为Either (Either [(Integer,Integer)] (Integer,Integer)) a

a有类似的问题。

要修复,您需要决定如何处理递归值。

轻松修复:

Left $ chk2 $ (4-2,4-2):next i

但是,我怀疑这是你想要的,因为这意味着你的所有结果都是 | lgst i==i!!0 = chk2 $ (4-2,4-2):next i | otherwise = chk2 $ next i 。 我不知道怎么做你想要的,因为我不确定你想要什么。

列表结果是什么意思?非列表结果意味着什么?

您可能想要做的是模式匹配递归的结果,转换Right,也许将其他结果附加到前面。

作为一个例子,我将构造一个具有类似类型签名的递归函数。让Right pair -> Left [pair]成为一个采用整数列表的函数,并且:

  • 如果列表的第一个元素是整个列表的最大值,则返回该元素
  • 否则,返回列表的子序列,其中每个子序列是它与子序列(或结尾)中下一个元素之间所有元素的最大值

要做到这一点:

foo

请注意我如何使用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] 对递归调用case的结果进行模式匹配。

答案 1 :(得分:1)

要解决Euler#4,你的Haskell似乎是一种非常尴尬的风格。尝试将其他语言的代码“移植”到Haskell中通常是一个坏主意,因为Haskell的范例非常不同。

你会发现使用列表推导at the Haskell Wiki的欧拉#4非常干净,明智的解决方案。当然不是唯一的解决方案,但它的可读性至少是当前代码的20倍。没有冒犯。

我(以及其他许多Haskellers)强烈建议Learn You a HaskellReal World Haskell学习如何处理Haskell方式的问题,根据我的经验,通常是创建小的,简单的帮助方法并组合它们解决方案。