【问题标题】:How can you use the result of a function as a variable in another function in Haskell?如何在 Haskell 中将函数的结果用作另一个函数的变量?
【发布时间】:2019-11-24 17:10:06
【问题描述】:

我正在尝试学习如何使用 Haskell,现在我必须编写一个程序,它需要一个整数 n 和一个字符串 k,并且该字符串的每个字母都将在字母表中向右移动 n 个位置。此时我得到了下一个代码:

import Data.Char

main = do
    x <- read getLine :: Int
    y <- getLine
    caesar x y

result :: String

rotate :: Int -> Char -> [Char]
rotate a b = [chr ((a + ord b) `mod` ord 'z' + ord 'a')]

caesar :: Int -> String -> ()
caesar moving text= do
    rotatespecific moving text 0
    putStrLn result


rotatespecific :: Int -> String -> Int -> ()
rotatespecific moving text place = do
    if place < length text
        then
            result ++ rotate (moving (text !! place))
            rotatespecific (moving text (place + 1))
        else
            if place == length text
                then
                    result ++ rotate (moving (text !! place))

但我无法编译它,因为它仍然给我同样的错误信息:

parse error (possibly incorrect indentation or mismatched brackets)
   |
28 |                     result ++ rotate (moving (text !! place))
   |                                                              ^

但我看不出我的语法有什么问题。我首先认为这与使用 Char 作为我的函数的参数有关,但我错了,因为 text !! place 应该给出一个 char 而不是 [char]。那我做的有什么问题呢?

经过一些编辑,我得到了这个,但它仍然不起作用:

import Data.Char

main = do
    xr <- getLine
    let x = read xr :: Int
    y <- getLine
    putStrLn (rotatespecific (x y 0))

rotate :: Int -> Char -> [Char]
rotate a b = [chr ((a + ord b) `mod` ord 'z' + ord 'a')]

rotatespecific :: Int -> String -> Int -> String
rotatespecific moving text place = do
    if place < length text
        then do
            help <- text !! place
            h <- rotate (moving help)
            a <- rotatespecific (moving text (place + 1))
            b <- h ++ a
            return b

        else
            if place == length text
                then do
                    return rotate (moving (text !! place))
                else
                    return ()

【问题讨论】:

  • 您将if 视为声明;仅仅因为它在do 块中并不意味着then 后面的表达式可以由一系列表达式组成。
  • 你也不能使用rotatespecific来“更新”result的值。
  • 除了您的解析错误之外,还有几处错误。你认为() 是什么?

标签: haskell


【解决方案1】:

直接的问题是每个if 都必须有一个else。最后你得到一个解析错误,因为解析器期待更多,即 else 对应 if place == length text

当您解决此问题时,您将遇到更多问题,因为您将 Haskell 视为一种命令式语言,而她不喜欢这样对待。好像你觉得

result ++ newstuff

将改变result,在其末尾添加newstuff。但是 Haskell 不会变异。相反,这个表达式result ++ newstuff 是连接resultnewstuff 时产生的列表,但result 本身保持不变。

ghci> let result = [1,2,3]
ghci> result ++ [4,5,6]
[1,2,3,4,5,6]
ghci> result
[1,2,3]

rotatespecific 必须return 旋转后的字符串,而不是试图改变它的存在。函数可以通信的唯一方式是返回从它们的参数计算的结果——它们可能不会像result 那样操纵任何“全局”状态。返回() 的函数保证是无用的。

rotatespecific :: Int -> String -> Int -> String

删除result“全局变量”(这并不意味着你认为它的意思)并专注于定义rotatespecific,使其返回旋转后的字符串。

我还建议现在将 maincaesar 注释掉,直到您在 ghci 中测试时 rotatespecific 编译并工作。

【讨论】:

  • 我改变了它,但现在它说有很多函数输入参数的类型不正确,例如: 无法匹配预期类型[Char]' with actual type Char -> [Char] '。我不知道那里出了什么问题,因为我认为他们是正确的。它说当我使用 x
  • @JoesdeJonge 该错误消息通常是因为您调用了具有错误数量参数的函数。另一个问题与 Haskell 建模 I/O 的方式有关。当您开始阅读有关 monad 的内容时,将对此进行讨论。为了激发你的好奇心,你可以写一行代码x &lt;- read &lt;$&gt; getLine
  • 我现在已将我当前的版本添加到上面的正文中。如果我现在尝试运行它,我会从第 15 行到最后收到错误消息,但我不明白为什么。它甚至说它不能做文字!即使 text 是字符串并且 place 是整数,也可以放置。之后的功能也不被接受。
  • @JoesdeJonge 如果这是一个新问题,您可能想对此提出一个新问题(这是一个口味问题,但请记住,SO 是 50% 是针对您的问题,而 50% 是对于将来遇到类似问题的其他人)。无论如何,“它不起作用”永远不会有帮助 - 始终包含特定的错误消息,以便我们知道我们在看什么。
  • @JoesdeJonge 但简短的回答是do&lt;-return 不属于像rotatespecific 这样的非单子函数。使用let .. inwhere 进行本地绑定,不要使用return(只需说出你想在没有关键字的情况下返回的内容,例如if place == length text then rotate moving (text !! place) else ...)。 return 是关于 Haskell 中的 monads,它不像在其他语言中那样工作(这在社区中被感叹;现在使用等效的 pure 来代替,return 可能很快就会被删除)
【解决方案2】:

我觉得现在是展示一个例子的合适时机,因为有很多小问题。我不会修复逻辑错误,但我已经修复了你的语法。希望这能让你摆脱困境。

rotatespecific :: Int -> String -> Int -> String
rotatespecific moving text place =
    if place < length text then
        -- use let .. in instead of do/bind (<-) in pure functions. 
        let help = text !! place

            -- multiple arguments are given after the function, no parentheses
            h = rotate moving help

            -- use parentheses around an argument if it is a complex expression
            -- (anything more than a variable name)
            a = rotatespecific moving text (place+1)

            b = h ++ a
        in b
    else
        if place == length text then
            rotate moving (text !! place)
        else
            undefined -- you must decide what String to return in this case.

在您使此功能按预期工作后,然后才打开这个密封的信封。 ♥️

rotatespecific :: Int -> String -> String rotatespecific 移动文本 = concatMap(旋转移动)文本

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-03-14
    • 1970-01-01
    • 1970-01-01
    • 2018-06-30
    • 1970-01-01
    • 2013-12-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多