2013-10-18 43 views
5

我试图编写一个类似于zip的函数,但不会丢弃额外的元素。我觉得我在某个地方犯了一个非常愚蠢的错误。我的zip版本有什么问题?

示例输入:

zipMaybe [1,2,3] [1,2] 

希望的输出:

[(Just 1, Just 1), (Just 2, Just 2), (Just 3, Nothing)] 

zipMaybe :: [a] -> [b] -> [(Maybe a, Maybe b)] 
zipMaybe (a:as) (b:bs) = (Just a, Just b) : zip as bs -- line with error 
zipMaybe (a:as) [] = (Just a, Nothing) : zip as [] 
zipMaybe [] (b:bs) = (Nothing, Just b) : zip [] bs 
zipMaybe _ _ = [] 

然而这将不编译。

Test.hs:2:49: 
    Couldn't match type `a' with `Maybe a' 
     `a' is a rigid type variable bound by 
      the type signature for 
      zipMaybe :: [a] -> [b] -> [(Maybe a, Maybe b)] 
      at Test.hs:1:13 
    Expected type: [Maybe a] 
     Actual type: [a] 
    In the first argument of `zip', namely `as' 
    In the second argument of `(:)', namely `zip as bs' 
    In the expression: (Just a, Just b) : zip as bs 
+2

你打电话'zip'而不是递归调用你的'zipMaybe'。 – Tarmil

+4

你可能会喜欢['align'](http://hackage.haskell.org/package/these-0.3/docs/Data-Align.html)。 –

+0

@DanielWagner谢谢,'padAlign'完全符合我的要求。 – mcjohnalds45

回答

9

你应该叫zipMaybe递归,而不是釜底抽薪香草zip,其中有错误的类型。 。

zipMaybe :: [a] -> [b] -> [(Maybe a, Maybe b)] 
zipMaybe (a:as) (b:bs) = (Just a, Just b) : zipMaybe as bs 
zipMaybe (a:as) [] = (Just a, Nothing) : zipMaybe as [] 
zipMaybe [] (b:bs) = (Nothing, Just b) : zipMaybe [] bs 
zipMaybe _ _ = [] 

顺便说一句,有此功能的更短的定义:

zipMaybe (x:xs) (y:ys) = (Just x, Just y) : zipMaybe xs ys 
zipMaybe xs  []  = [(Just x, Nothing) | x <- xs] 
zipMaybe []  ys  = [(Nothing, Just y) | y <- ys] 
+2

'map(\ x - >(Just x,Nothing))xs'而不是'map','zip'和'repeat'如何? –

+0

@DanielWagner:那我宁愿理解。查看更新的答案。 –

+0

'map'可能看起来比这里的理解更清晰 – alternative