Haskell:期望类型[Char]实际类型[[Char]]

时间:2016-01-04 12:18:51

标签: haskell

我试图做一个检查功能,但我收到了错误:

Couldn't match expected type `Char' with actual type `[Char]'
Expected type: [Char]
  Actual type: [[Char]]
In the first argument of `isHorizontal', namely `str'
In the expression: isHorizontal str number

这是触发它的功能:

upCheck :: [[Char]] -> Int -> [Int] -> Bool
upCheck tableArr number posArr = do
    let arv = findVertIndex (tableArr !! (posArr !! 0)) number
    let str = tableArr !! (posArr !! 0)
    if ((posArr !! 0) == 1)
      then False
      else if isHorizontal str number
        then False
        else if (tableArr !! ((posArr !! 0)-1)) !! arv /= 'x'
          then False
          else True

其中tableArr是包含字符串的数组:["2323","3232","3231","3232"]posArr是包含正确位置的数组,例如[1,3]number是我们要检查的号码,让我们说1

现在isHorizontal函数就是这个,它基本告诉我同一行中是否有两个元素。

isHorizontal :: [Char] -> Int -> Bool
isHorizontal [] _ = False
isHorizontal [x] _ = False
isHorizontal (x:y:xs) number =
   if (firstCheck x && firstCheck y)
   then (if digitToInt(x) == number && digitToInt(y) == number then  True else isHorizontal xs number)else isHorizontal (y:xs) number

但是函数isHorizo​​ntal适用于输入" 55x32"例如5,所以问题出在我的upCheck功能中。从它的外观来看,代码:tableArr !! (posArr !! 0)也应该给一个字符串,所以这应该适合isHorizo​​ntal函数,但它不会...

我错过了什么?

编辑:

将类型添加到函数后,错误更改为:

 Couldn't match expected type `[Char]' with actual type `Char'
Expected type: [[[Char]]]
  Actual type: [[Char]]
In the first argument of `(!!)', namely `tableArr'
In the first argument of `findVertIndex', namely
  `(tableArr !! (posArr !! 0))'

1 个答案:

答案 0 :(得分:4)

您正在尝试在此处定义纯函数。 (那个伟大的,纯粹的功能给你referential transparency:非常好的推理你的程序将如何表现!)

但是,do符号是程序性的。当你正在做 impure 的东西时(例如,如果你有签名[[Char]] -> Int -> [Int] -> IO Bool,你需要那个,这意味着你的“功能”是也允许做不纯的顺序IO操作)。但是在编写简单的纯函数时,你并不需要这样做。

所以而不是

upCheck tableArr number posArr = do
    let arv = findVertIndex (tableArr !! (posArr !! 0)) number
    let str = tableArr !! (posArr !! 0)
    if ((posArr !! 0) == 1)
      then False
      else if isHorizontal str number
        then False
        else if (tableArr !! ((posArr !! 0)-1)) !! arv /= 'x'
          then False
          else True
你可能想要

upCheck tableArr number posArr
  = let arv = findVertIndex (tableArr !! (posArr !! 0)) number
        str = tableArr !! (posArr !! 0)
    in if ((posArr !! 0) == 1)
        then False
        else if isHorizontal str number
              then False
              else if (tableArr !! ((posArr !! 0)-1)) !! arv /= 'x'
                    then False
                    else True

这看起来很相似,但实际上做了一些完全不同的事情:而不是用do(仅适用于像IO这样的monad中的一系列步骤进行硬烘焙),你只需告诉它编译器的一些定义,但可以自由地找出评估这些定义的最佳顺序。

实际上,按照

这样的方式更多地写出定义是习惯做法
upCheck tableArr number posArr
     = if ((posArr !! 0) == 1)
        then False
        else if isHorizontal str number
              then False
              else if (tableArr !! ((posArr !! 0)-1)) !! arv /= 'x'
                    then False
                    else True
  where arv = findVertIndex (tableArr !! (posArr !! 0)) number
        str = tableArr !! (posArr !! 0)

实际上与let...in的代码完全相同。

请注意if staments链可以更好地编写为 guards

upCheck tableArr number posArr
     | posArr!!0 == 1                                = False
     | isHorizontal str number                       = False
     | tableArr !! ((posArr !! 0)-1)) !! arv /= 'x'  = False
     | otherwise                                     = True
  where arv = findVertIndex (tableArr !! (posArr !! 0)) number
        str = tableArr !! (posArr !! 0)

......但实际上,在编写 boolean 函数时,您根本不需要条件。整个野兽等同于简单

upCheck tableArr number posArr
    = not (   posArr!!0 == 1
           || isHorizontal str number
           || tableArr !! ((posArr !! 0)-1)) !! arv /= 'x'
          )
  where arv = findVertIndex (tableArr !! (posArr !! 0)) number
        str = tableArr !! (posArr !! 0)

这在大多数编程语言中都是可行的,而不仅仅是在Haskell中。

实际上,do本身并不纯洁。它使用 monads ,恰好允许(除此之外)将不纯的代码嵌入到纯Haskell中(以一种非常安全的方式)。但是你可能想稍后了解它。