所以我有以下功能:
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)] ,即后者两名警卫。基本的问题是后两个警卫..如果我拿出递归,一切正常,但我不知道如何在返回函数本身时定义类型签名。
答案 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 Haskell和Real World Haskell学习如何处理Haskell方式的问题,根据我的经验,通常是创建小的,简单的帮助方法并组合它们解决方案。