如何处理Haskell列表推导II

时间:2015-04-30 08:45:26

标签: haskell

我在列表操作中实现了一个可能类型的问题!

我需要做的是:

ljoin [(2,"S"),(1,"J")] [(2,1),(2,2),(3,4)]
     outputs: [(2,"S",Just 1),(2,"S",Just 2),(1,"J",Nothing)]

到目前为止我所写的内容:

ljoin :: Eq a => [(a,b)] -> [(a,c)] -> [(a,b,Maybe c)]
ljoin xs ys = [if xs==ys then (xa, xb, Just yc) else (xa, xb, Nothing) | (xa, xb) <- xs, (ya, yc) <- ys]

产生错误:

Inferred type is not general enough
*** Expression    : ljoin
*** Expected type : Eq a => [(a,b)] -> [(a,c)] -> [(a,b,Maybe c)]
*** Inferred type : Eq a => [(a,b)] -> [(a,b)] -> [(a,b,Maybe b)]

我是按照正确的方式做到这一点,只是需要坚持下去,直到我发现我做错了,或者有更好的方法?

2 个答案:

答案 0 :(得分:7)

子表达式xs == ys强制xsys具有相同的类型。

(==) :: (Eq a) => a -> a -> Bool

在您的两个列表中调用此方法会强制[(a,b)] = [(a,c)],因此b = c。但是你已经在类型中声明你有两个独立的类型变量,所以不允许统一这些变量。

在我看来,你应该比较你得到的实际的第一个元素,而不是整个列表。

答案 1 :(得分:2)

根据你的例子,我相信你想要的ljoin是这样的:

for each element (xa, xb) of xs
  if there are elements in ys that xa == ya, then
    for each of these element (ya, yb) generates a (xa, xb, Just yb)
  else
    generates a (xa, xb, Nothing)

这可以直接翻译成Haskell代码:

ljoin xs ys = concatMap join xs
  where join (xa, xb) = case filter (\(ya, yb) -> xa == ya) ys of
                         [] -> [(xa, xb, Nothing)]
                         ys' -> map (\(_, yb) -> (xa, xb, Just yb)) ys'