【问题标题】:Haskell Input to create a String ListHaskell 输入创建字符串列表
【发布时间】:2015-05-08 14:04:27
【问题描述】:

我想允许用户从 Haskell 中的一系列输入构建一个列表。

getLine 函数将被递归调用,直到输入停止情况(“Y”),此时返回列表。

我知道函数需要采用与下面类似的格式。我无法分配正确的类型签名 - 我想我需要在某处包含 IO 类型。

getList :: [String] -> [String]
getList list =  do line <- getLine
                   if line ==  "Y"
                      then return list
                      else getList (line : list)

【问题讨论】:

  • 如果它执行IO,那么最后一个-&gt;之后的类型必须是IO something
  • 你也可以删除你给它的签名并使用 GHCi 检查编译器推断的签名是什么::load myfile.hs; :type getList.
  • 代码中的getCast 函数是什么?
  • 对不起 getCast 在我的问题中是一个错误。应该是 getList。

标签: string list haskell recursion


【解决方案1】:

因此,您需要了解很多事情。其中之一是IO x 类型。这种类型的值是一个计算机程序,它在以后运行时会做一些事情并产生一个x 类型的值。所以getLine 自己并没有任何事情;它只是某种程序。与let p = putStrLn "hello!" 相同。我可以将p 多次排序到我的程序中,它会多次打印hello!,因为IO () 是一个程序,作为Haskell 恰好能够谈论和操作的值。如果这是 TypeScript,我会说 type IO&lt;x&gt; = { run: () =&gt; Promise&lt;x&gt; },并强调该类型表示副作用操作尚未运行

那么当值是程序时,我们如何操作这些值,例如获取当前系统时间的程序?

将这些程序链接在一起的最基本方法是采用一个产生xIO x)的程序,然后是一个采用x并构造一个产生y的程序的Haskell函数(x -&gt; IO y 并将它们组合成一个生成的程序,生成yIO y。)这个函数称为&gt;&gt;=,发音为“bind”。事实上,如果我们添加一个程序,这种方式是通用的它采用x 类型的任何 Haskell 值并生成一个程序,该程序什么都不做并产生该值 (return :: x -&gt; IO x)。这允许您使用例如 Prelude 函数 fmap f = (&gt;&gt;= return . f),它接受 a -&gt; b 并应用将其发送到IO a 以生成IO b

所以说getLine &gt;&gt;= \line -&gt; putStrLn (upcase line ++ "!") 之类的东西很常见,我们发明了do-notation,写成这样

do 
    line <- getLine
    putStrLn (upcase line ++ "!")

请注意,这是相同的基本交易;对于某些y,最后一行需要是IO y

在 Haskell 中你需要知道的最后一件事是实际运行这些东西的约定。也就是说,在您的 Haskell 源代码中,您应该创建一个名为 Main.mainIO ()(一个值无关紧要的程序),并且 Haskell 编译器应该采用您描述的这个程序,并给出它作为可执行文件提供给您,您可以随时运行。作为一个非常特殊的情况,如果您在顶层生成 IO x 表达式,GHCi 解释器会注意到并立即为您运行它,但这与语言的其余部分非常不同作品。大部分情况下,Haskell 说,描述一下程序,我会把它给你。

现在您知道 Haskell 没有魔法,而 Haskell IO x 类型只是计算机程序作为值的静态表示,而不是当您“减少”它时会产生副作用的东西(喜欢它是其他语言),我们可以转向您的getList。显然,getList :: IO [String] 根据您所说的最有意义:一个允许用户从一系列输入构建列表的程序。

现在要构建内部结构,您猜对了:我们必须从 getLine 开始,要么完成列表,要么继续接受输入,将行添加到列表中:

getList = do
    line <- getLine
    if line == 'exit' then return []
                      else fmap (line:) getList

您还确定了另一种方法,这取决于获取字符串列表并生成新列表:

getList :: IO [String]
getList = fmap reverse (go []) where 
    go xs = do 
        x <- getLine
        if x == "exit" then return xs
                       else go (x : xs)

可能还有其他几种方法可以做到这一点。

【讨论】:

  • 感谢您解释 IO 类型。
猜你喜欢
  • 1970-01-01
  • 2020-11-24
  • 2020-06-26
  • 2017-03-11
  • 2014-03-14
  • 1970-01-01
  • 1970-01-01
  • 2017-05-18
  • 1970-01-01
相关资源
最近更新 更多