Haskell:如何读取用户输入以在 do 块内的函数中使用?

-2 io haskell palindrome

我正在尝试在 Haskell 中运行一个简单的回文程序,但我想请求用户输入在程序中使用。

代码:

palindrome :: String -> Bool
palindrome x = x == reverse x
main = do
  putStrLn "Brendon Bailey CSCI 4200-DB"
  putStrLn "Enter word to test for Palindrome"
  palindrome <- getLine
  putStrLn "Thanks"
Run Code Online (Sandbox Code Playgroud)

该代码有效,但它只显示“谢谢”。如果我排除该块的最后一行,我会得到“do 块的最后一行必须是表达式”,如果我在 do 块上方包含实际的回文代码,我会收到错误消息,说我需要一个“let”语句,但合并一个会导致更多错误。我是 Haskell 的新手(以及一般的函数式编程。我使用 java、c++ 和 web 语言)我认为这里的解释很简单,但在阅读了 Haskell 上的输入输出文档后,我仍然无法找出正确的方法完成这个。

我这样做是因为我的作业规定我必须在程序运行时显示类信息。回文部分在没有 do 块的情况下工作正常。我只是尝试在测试回文之前自动输出文本。另外,如何设置 haskell 脚本在加载时运行?我不希望用户必须输入“main”,我希望它能够运行。

编辑:

palindrome :: String -> Bool
palindrome x = x == reverse x
main = do
  putStrLn "Brendon Bailey CSCI 4200-DB"
  putStrLn "Enter Word"
  x <- getLine
  palindrome x
  putStrLn "thanks"
Run Code Online (Sandbox Code Playgroud)

这也是行不通的。如何让用户输入在回文中使用???

如果代码:

palindrome :: String -> Bool
palindrome x = x == reverse x
Run Code Online (Sandbox Code Playgroud)

当在 GHCi 中输入“回文“etc””时有效,那么为什么我的第二个代码版本不做同样的事情???

编辑2:不要忘记将 print 语句括在括号中,否则 Haskell 会认为单独的输入是单独的参数。愚蠢的错误但很容易犯。

AJF*_*mar 5

这个问题是多个问题合而为一的,所以我将尝试解决每个问题。我将以不同的顺序来阐述这些问题。

\n\n

在我们开始之前,必须要说的是,您对 Haskell 的工作方式存在严重的误解。我强烈推荐阅读Learn a Haskell for Great Good,这可能看起来很幼稚,但实际上是函数式编程的精彩介绍,而且实际上是我们许多人开始学习 Haskell 的方式。

\n\n

问题 1:编译、GHC 和 Haskell 可执行文件

\n\n
\n

(...) 如何设置 haskell 脚本在加载时运行?我不希望用户必须输入“main”,我希望它能够运行。

\n
\n\n

您将Python、Javascript 或 Ruby 等解释型脚本语言与编译型脚本语言混淆了脚本语言与 C、Java 或 Haskell 等

\n\n

解释性语言的程序由计算机上的程序运行,该程序包含有关如何解释所编写文本的信息,因此称为“解释型”。然而,编写编译语言,然后将文本转换为机器代码,人类几乎无法阅读,但计算机可以快速运行。

\n\n

当我们在 Haskell 中编写一个完整的可执行程序时,我们期望使用 Glasgow Haskell 编译器 GHC 来编译它(而不是GHCi)来编译它。这看起来像这样:

\n\n
$ cat MyProgram.hs\nmain :: IO ()\nmain = putStrLn "This is my program!"\n$ ghc MyProgram.hs\n[1 of 1] Compiling Main             ( MyProgram.hs, MyProgram.o )\nLinking MyProgram ...\n$ ./MyProgram\nThis is my program!\n
Run Code Online (Sandbox Code Playgroud)\n\n

现在,MyProgram.hsGHC 将 Haskell 源代码文件转换为可执行文件MyProgram. 我们定义了一个名为 的 IO 操作,main来告诉编译器我们希望它从哪里开始。这称为入口点,是创建独立可执行文件所必需的。这就是 Haskell 程序的创建和运行方式。

\n\n

至关重要的是,GHCi 并不是Haskell程序的运行方式。GHCi 是一个用于试验 Haskell 函数和定义的交互式环境。GHCi 允许您计算表达式(例如palindrome "Hello"、 或main),但并不旨在作为运行 Haskell 程序的方式,就像 python 的 IDLE 用于 Python 程序一样。

\n\n

问题 2:函数与 IO 操作

\n\n
\n

(...) 如果您只有在 do 块之外的回文代码,并且用户在 GHCi 中输入“回文“etc””,程序将返回布尔值作为输出 (...)

\n
\n\n

Haskell 的行为与您可能习惯的语言不同Haskell 中的函数不是程序。当您定义函数时palindrome,您为计算机提供了一种将 a 转换String为 a 的方法Bool。你没有告诉它如何Bool以任何方式输出它。因此,有一个额外的步骤:IOmonad。

\n\n

Haskell 程序在某种程度上被表示为数据,因此有点奇怪的类型签名main :: IO ()。我不会在这里详细解释 monad,但简单地说,在 -block 中do,您只能声明任何类型的IO a事物a。所以,当你写道:

\n\n
main = do\n    -- (...)\n    palindrome x\n    -- (...)\n
Run Code Online (Sandbox Code Playgroud)\n\n

这没有道理。这样想:如何“运行”或“执行” a Bool?这是一个布尔值,而不是一个程序!

\n\n

然而,有一个名为 的函数print,它可以让您准确地做到这一点。你的线路应该是:

\n\n
main = do\n    -- (...)\n    print (palindrome x)\n    -- (...)\n
Run Code Online (Sandbox Code Playgroud)\n\n

我不会讨论prints 类型签名,但请放心,它确实返回一个IO (),这允许我们将其放入 -block 中do。顺便说一句,如果你写:

\n\n
palindrome :: String -> Bool\npalindrome x = x == reverse x\n\nmain = do\n  putStrLn "Brendon Bailey CSCI 4200-DB"\n  putStrLn "Enter Word"\n  x <- getLine\n  print (palindrome x)\n  putStrLn "thanks"\n
Run Code Online (Sandbox Code Playgroud)\n\n

...并使用 GHC 编译文件,假设您确实希望程序输出True或,您将获得所需的效果False。事实上,我将其编译为Palindromes.hs,结果如下:

\n\n
$ ghc Palindromes.hs \n[1 of 1] Compiling Main             ( Palindromes.hs, Palindromes.o )\nLinking Palindromes ...\n$ ./Palindromes\nBrendon Bailey CSCI 4200-DB\nEnter Word\namanaplanacanalpanama\nTrue\nthanks\n
Run Code Online (Sandbox Code Playgroud)\n\n

问题3:GHCi作为测试环境

\n\n
\n

当在 GHCi 中输入“回文“etc””时,[我的代码] 可以工作,那么为什么我的第二个代码版本不做同样的事情???

\n
\n\n

如前所述,GHCi 与 GHC 不同,它是在编写独立程序之前测试和“玩”Haskell 代码的环境。

\n\n

在 GHCi 中,您编写表达式,然后对它们求值(使用 GHC 的机制),打印结果,然后循环,因此,这种系统通常称为读取-求值-打印-循环,或 REPL 。

\n\n

让我们检查一下 GHCi 中的一些代码:

\n\n
\xce\xbb let plusOne n = n + 1\n\xce\xbb plusOne 5\n6\n
Run Code Online (Sandbox Code Playgroud)\n\n

第一行定义了一个我们稍后可以使用的值(这里是一个函数)。然而,第二行不是定义,而是表达式。因此,GHCi 对其进行评估并打印结果。

\n\n

GHCi 还可以执行 IO 操作:

\n\n
\xce\xbb let myProgram = putStrLn "Hello!"\n\xce\xbb myProgram\nHello!\n
Run Code Online (Sandbox Code Playgroud)\n\n

这是有效的,因为在 Haskell 中评估 IO 操作相当于执行它们:这就是 Haskell 的设计工作方式 - 只要您掌握了它,这就是一个真正出色的想法。

\n\n

尽管我们看到了这些相似之处,但GHCi 并不等同于 Haskell 程序,正如人们在使用 Python 后所期望的那样。不幸的是,GHCi 与“真正的”Haskell 代码几乎没有相似之处,因为 Haskell 的工作方式与大多数其他语言根本不同。

\n\n

GHCi 只不过是一种快速查看代码结果的有用方法,以及我在此不解释的其他有用信息。

\n\n

其他要点

\n\n

单子是这里问题的关键部分。StackOverflow 上有很多很多关于 Monad 的问题,因为它们往往是一个症结所在,所以您可能有的任何问题都可能在这里。这让事情变得很困难,因为如果不了解 Monad,就无法充分理解 Haskell IO。LYAH有一个关于 Monad 的章节。

\n