【问题标题】:Expected type [Int] - Actual type [[int]] - Haskell Recursion预期类型 [Int] - 实际类型 [[int]] - Haskell 递归
【发布时间】:2021-05-28 06:52:01
【问题描述】:

我正在处理 Haskell 中的一个函数,该函数接收一个包含矩形宽度和高度的字符串(该字符串的格式类似于“宽度长度”或“1 3”)。然后它递归地计算出填充该矩形的正方形的边长,并返回填充矩形的每个正方形的所有边长(它只会返回每个正方形的一个边长,因为正方形只有一个唯一的边长)。

我遇到的问题是,每当我运行下面的代码时,Haskell 都会告诉我,当预期类型 [Int] 时,我试图返回类型 [[Int]]。我对 Haskell 很陌生,并且在将 Int 放入集合并返回之前,努力弄清楚究竟是什么导致我的 Int 变成了 [Int]。

module MakeSquares where

import Data.List

solve :: String -> [Int]

solve s
 |lengthOne == lengthTwo = return [lengthOne]
--If we run into any problems then add a where statement definining the equation in "show"
 |lengthOne > lengthTwo = do f <- solve (intercalate " " [show lengthOneMinusTwo, show lengthTwo])
                             return (lengthTwo:f)
 |lengthOne < lengthTwo = do f <- solve (intercalate " " [show lengthTwoMinusOne, show lengthOne])
                             return (lengthOne:f)
 where
  input = words s
  stringLengthOne = input!!0
  stringLengthTwo = input!!1
  lengthOne = read stringLengthOne::Int
  lengthTwo = read stringLengthTwo::Int
  lengthOneMinusTwo = lengthOne - lengthTwo
  lengthTwoMinusOne = lengthTwo - lengthOne

Haskell 在尝试运行时向我发送的错误如下。

MakeSquares.hs:8:28: error:
    * Couldn't match type `[Int]' with `Int'
      Expected type: [Int]
        Actual type: [[Int]]
    * In the expression: return [lengthOne]
      In an equation for `solve':
          solve s
            | lengthOne == lengthTwo = return [lengthOne]
            | lengthOne > lengthTwo
            = do f <- solve (intercalate " " [show lengthOneMinusTwo, ....])
                 return (lengthTwo : f)
            | lengthOne < lengthTwo
            = do f <- solve (intercalate " " [show lengthTwoMinusOne, ....])
                 return (lengthOne : f)
            where
                input = words s
                stringLengthOne = input !! 0
                stringLengthTwo = input !! 1
                lengthOne = read stringLengthOne :: Int
                ....
  |
8 |  |lengthOne == lengthTwo = return [lengthOne]
  |                            ^^^^^^^^^^^^^^^^^^

MakeSquares.hs:11:30: error:
    * Couldn't match type `[Int]' with `Int'
      Expected type: [Int]
        Actual type: [[Int]]
    * In a stmt of a 'do' block: return (lengthTwo : f)
      In the expression:
        do f <- solve
                  (intercalate " " [show lengthOneMinusTwo, show lengthTwo])
           return (lengthTwo : f)
      In an equation for `solve':
          solve s
            | lengthOne == lengthTwo = return [lengthOne]
            | lengthOne > lengthTwo
            = do f <- solve (intercalate " " [show lengthOneMinusTwo, ....])
                 return (lengthTwo : f)
            | lengthOne < lengthTwo
            = do f <- solve (intercalate " " [show lengthTwoMinusOne, ....])
                 return (lengthOne : f)
            where
                input = words s
                stringLengthOne = input !! 0
                stringLengthTwo = input !! 1
                lengthOne = read stringLengthOne :: Int
                ....
   |
11 |                              return (lengthTwo:f)
   |                              ^^^^^^^^^^^^^^^^^^^^

MakeSquares.hs:11:48: error:
    * Couldn't match expected type `[Int]' with actual type `Int'
    * In the second argument of `(:)', namely `f'
      In the first argument of `return', namely `(lengthTwo : f)'
      In a stmt of a 'do' block: return (lengthTwo : f)
   |
11 |                              return (lengthTwo:f)
   |                                                ^

MakeSquares.hs:13:30: error:
    * Couldn't match type `[Int]' with `Int'
      Expected type: [Int]
        Actual type: [[Int]]
    * In a stmt of a 'do' block: return (lengthOne : f)
      In the expression:
        do f <- solve
                  (intercalate " " [show lengthTwoMinusOne, show lengthOne])
           return (lengthOne : f)
      In an equation for `solve':
          solve s
            | lengthOne == lengthTwo = return [lengthOne]
            | lengthOne > lengthTwo
            = do f <- solve (intercalate " " [show lengthOneMinusTwo, ....])
                 return (lengthTwo : f)
            | lengthOne < lengthTwo
            = do f <- solve (intercalate " " [show lengthTwoMinusOne, ....])
                 return (lengthOne : f)
            where
                input = words s
                stringLengthOne = input !! 0
                stringLengthTwo = input !! 1
                lengthOne = read stringLengthOne :: Int
                ....
   |
13 |                              return (lengthOne:f)
   |                              ^^^^^^^^^^^^^^^^^^^^

MakeSquares.hs:13:48: error:
    * Couldn't match expected type `[Int]' with actual type `Int'
    * In the second argument of `(:)', namely `f'
      In the first argument of `return', namely `(lengthOne : f)'
      In a stmt of a 'do' block: return (lengthOne : f)
   |
13 |                              return (lengthOne:f)
   |                                                ^

我一直在尝试调试这个程序的方式是按照我认为程序会在 ghci 中发送命令的顺序手动发送命令。不幸的是,我还没有找到导致我输入错误的原因。

【问题讨论】:

  • 你真的不应该使用!! 或字符串作为输入。在 haskell 中,您应该使用数据类型来表示复杂的数据结构

标签: haskell recursion


【解决方案1】:

问题在于您的 do 块。在您正确理解 monad 之前,请勿将 doreturn 用于除 IO 排序之外的任何内容。

你想写的是

 |lengthOne == lengthTwo = [lengthOne]
 |lengthOne > lengthTwo = let f = solve (intercalate " " [ show lengthOneMinusTwo
                                                         , show lengthTwo ])
                          in (lengthTwo:f)
 |lengthOne < lengthTwo = let f = solve (intercalate " " [ show lengthTwoMinusOne
                                                         , show lengthOne ])
                          in (lengthOne:f)

或者,使用模式保护,

 | lengthOne == lengthTwo = [lengthOne]
 | lengthOne > lengthTwo
 , f <- solve (intercalate " " [show lengthOneMinusTwo, show lengthTwo])
         = lengthTwo:f
 | lengthOne < lengthTwo
 , f <- solve (intercalate " " [show lengthTwoMinusOne, show lengthOne])
         = lengthOne:f

老实说,传递字符串来传达数字列表是一种非常糟糕的风格。看起来这个函数实际上应该有类型

solve :: Int -> Int -> [Int]

然后你就可以抛弃所有的wordsreadshowintercalate crud。

【讨论】:

    【解决方案2】:

    return 不像在过程语言中那样表达这是函数的resultreturn 将项目包装在单子上下文中。因为这里你的函数的返回类型是[Int]return 使用Monad[] 实例,return 因此将项目包装在一个单例列表中。

    你应该使用:

    solve :: String -> [Int]
    solve s
     | lengthOne == lengthTwo = [lengthOne]  -- &leftarrow; no return
     | lengthOne > lengthTwo = do
        f <- solve (intercalate " " [show lengthOneMinusTwo, show lengthTwo])
        (lengthTwo:f)  -- &leftarrow; no return
     |lengthOne < lengthTwo = do
        f <- solve (intercalate " " [show lengthTwoMinusOne, show lengthOne])
        (lengthOne:f)  -- &leftarrow; no return

    但是现在我们将遇到另一个问题:f 的类型为 Int,但是这不适用于此处的 (lengthOne:f), since that expects fto be a list. You do not need to usedo`,只需使用子表达式或 let … in …

    solve s
     | lengthOne == lengthTwo = [lengthOne]
     | lengthOne > lengthTwo =
        --            &downarrow; subexpression
        (lengthTwo: solve (intercalate " " [show lengthOneMinusTwo, show lengthTwo]))  
     |lengthOne < lengthTwo =
        --            &downarrow; subexpression
        (lengthOne:solve (intercalate " " [show lengthTwoMinusOne, show lengthOne]))

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-09-14
      • 2017-04-07
      • 1970-01-01
      • 1970-01-01
      • 2015-06-08
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多