首页 > 解决方案 > 无法将预期类型“[a1]”与实际类型“([a1],[a1])”匹配

问题描述

我是使用 Haskell 编码的新手,并且一直坚持我的教授希望我们编写的代码。我应该将一个列表处理成一对列表,如下所示:

deal [1,2,3,4,5,6,7] = ([1,3,5,7], [2,4,6])

但我在我的“xs”和“ys”上都收到了这个错误

* Couldn't match expected type `[a1]'
                  with actual type `([a1], [a1])'
    * In the expression: deal xs
      In an equation for `xs': xs = deal xs
      In an equation for `deal':
          deal (x : y : xs : ys)
            = (x : xs, y : ys)
            where
                xs = deal xs
                ys = deal ys
    * Relevant bindings include xs :: [a1] (bound at lab2.hs:16:17)
   |
   |                 xs = deal xs
   |                      ^^^^^^^

这是我的代码:

deal :: [a] -> ([a],[a])
deal [] = ([], [])
deal [x] = ([x], [])
deal (x:y:xs:ys) = (x:xs,y:ys)
    where
        xs = deal xs
        ys = deal ys

标签: haskell

解决方案


这是合乎逻辑的,因为在这里你的deal xsanddeal ys将返回,给定签名一个 2 元组列表,并且xs具有 type [a]。请注意,通过使用相同的名称,您在这里做了一个递归表达式,这将不起作用。多次使用相同的名称不是一个好主意。如果您打开警告,编译器通常会对此发出警告。

您可能想要调用列表dealrest,然后检索您用作尾部的两个列表:

deal :: [a] -> ([a],[a])
deal [] = ([], [])
deal [x] = ([x], [])
deal (x:y:rest) = (x:xs, y:ys)
    where (xs, ys) = deal rest

或者我们可以利用(***) :: a b c -> a b' c' -> a (b, b') (c, c')

import Control.Arrow((***))

deal :: [a] -> ([a],[a])
deal [] = ([], [])
deal [x] = ([x], [])
deal (x:y:rest) = ((x:) *** (y:)) (deal rest)

另一种方法是每次交换元组,并附加到另一边:

import Control.Arrow(first)
import Data.Tuple(swap)

deal :: [a] -> ([a],[a])
deal [] = ([], [])
deal (x:xs) = first (x:) (swap (deal xs))

因此,我们可以将其定义为一种foldr模式:

import Control.Arrow(first)
import Data.Tuple(swap)

deal :: Foldable f => f a -> ([a],[a])
deal [] = foldr ((. swap) . first . (:)) ([], [])

这给了我们预期的结果:

Prelude> deal [1,2,3,4,5,6,7]
([1,3,5,7],[2,4,6])

推荐阅读