Haskell:无法匹配类型?

时间:2018-08-18 20:47:05

标签: haskell

关于类型匹配的最后一个问题(目前至少是哈哈)。

在代码底部的以下 takeS 公式中,我想在Snoc列表中输出特定数量的元素,定义如下:

data ListS a = NilS 
              |Snoc (ListS a) a deriving Show

initS :: ListS a -> ListS a
initS NilS          = error "Empty List"
initS (Snoc a b)    = a

lastS :: ListS a -> a
lastS NilS          = error "Empty List"
lastS (Snoc _ b)    = b

headS :: ListS a -> a
headS NilS          = error "Empty List"
headS (Snoc NilS b) = b
headS (Snoc a b)    = headS a

tailS :: ListS a -> ListS a
tailS NilS          = error "Empty List"
tailS (Snoc NilS a) = NilS
tailS (Snoc a b)    = (Snoc (tailS a) b)    

reverseS :: ListS a -> ListS a
reverseS NilS = NilS
reverseS l = (Snoc (reverseS(tailS(l))) (headS l))

takeS :: Int -> ListS a -> ListS a
takeS 0 _    = NilS
takeS _ NilS = error "Empty List"
takeS n l    = if n >= len(l) then 
               takeAux len(l) reverseS(l) else takeAux n reverseS(l) where
                   takeAux 0 l = l
                   takeAux n l = (Snoc (takeAux (n-1) initS(l)) (lastS l)) 

当我尝试编译时,出现以下错误:

C:\Users\Google Drive\Ejercicio01.hs:31:20: error:
    * Couldn't match type `ListS a4' with `ListS a3 -> ListS a3'
      Expected type: t -> (ListS a3 -> ListS a3) -> ListS a4 -> ListS a4
        Actual type: t -> ListS a4 -> ListS a4
    * In an equation for `takeS':
          takeS n l
            = if n >= len (l) then
                  takeAux len (l) reverseS (l)
              else
                  takeAux n reverseS (l)
            where
                takeAux 0 l = l
                takeAux n l = (Snoc (takeAux (n - 1) initS (l)) (lastS l))
    * Relevant bindings include
        takeAux :: t -> (ListS a3 -> ListS a3) -> ListS a4 -> ListS a4
          (bound at C:\Users\Google Drive\Ejercicio01.hs:31:20)
   |
97 |                    takeAux 0 l = l
   |                    ^^^^^^^^^^^^^^^^...
Failed, no modules loaded.

正如我所看到的,我试图输出相同类型的列表,但是Haskell说我在调用辅助函数时创建了不同类型的列表。那是对的吗?在一开始处理此类错误时,它可能会造成一些混乱,因此,除了通过指出问题所在来帮助我之外,我还想知道是否有一个存储库或指南来更好地了解Haskell的复杂性。

谢谢!

2 个答案:

答案 0 :(得分:2)

您编写的应用程序不是正确的。应该是

takeS n l = if n >= (len l) then 
           takeAux (len l) (reverseS l) else takeAux n (reverseS l) where
               takeAux 0 l = l
               takeAux n l = (Snoc (takeAux (n-1) (initS l)) (lastS l)) 

括号在Haskell中用于分组,而不是作为运算符使用(将元组结构放在一边)。

请注意,您的代码中几乎没有不一致之处:

  1. 您的代码中是否有与标准Prelude冲突的名称? len是衡量列表长度的标准函数。

  2. reverse是二次的。

  3. 为什么当您拥有init并且没有持续时间(即在O(1)中)时,为什么在这里需要headStailS

  4. takeS合同中存在不一致之处:takeS 2 NilS是错误,而takeS 3 (Snoc NilS 42)返回了tsil。在最后一场比赛中,您真的不需要长度。

答案 1 :(得分:2)

类型检查器以一种非常有趣的方式弄乱了takeAux的类型。因此错误消息令人困惑。在where子句{{1}中,在takeAux上方写一个类型签名,然后haskell将为您提供更好的错误信息,该错误信息集中在另一行。

作为一般规则,当您在没有类型签名的辅助功能上遇到类型检查错误并且原因不明显时,添加类型签名将为您提供更清晰的错误消息。它还有助于记录您的代码。