【问题标题】:Haskell: IO [String] to [String] [duplicate]Haskell:IO [String] 到 [String] [重复]
【发布时间】:2016-01-03 14:00:48
【问题描述】:

现在,这是一个经常经历 Stack Overflow 的线程。这也被其他网站所覆盖,但我仍然无法完全理解它。我从这个网站上读过不同的东西,我在底部链接它们,但现在是问题。

像往常一样,我正在尝试从文件中读取行:

module BoardData where

readTable = do
  s <- readFile "projekt-board.txt"
  let content = lines s
  let removeEnd = init(content)
  let removeHead = tail(removeEnd)
  return removeHead

printTable [] = putStr ""
printTable [x] = putStrLn x
printTable (x:xs) = do
  let element = x
  putStrLn element
  printTable xs

我无法理解为什么我在函数 readTable 中没有得到 IO [String] -&gt; [String] 异常,但是用 readTable 的参数调用 printTable 会给我一个错误。

  • 有没有办法欺骗IO [String] 类型,可能是通过访问IO [String] 列表中的每个元素,然后创建一个新的纯元素?
  • 或者我仍然可以使用IO [String] 类型进行基本的列表操作(但是到目前为止我已经失败了)?

我读过的一些阅读材料,但现在让我更加困惑:


[编辑:调用时抛出错误 ]

*BoardData> let it = printTable readTable in it

<interactive>:1:21: error:
    • Couldn't match expected type ‘[String]’
                  with actual type ‘IO [String]’
    • In the first argument of ‘printTable’, namely ‘readTable’
      In the expression: printTable readTable
      In an equation for ‘it’: it = printTable readTable

【问题讨论】:

  • 你想要readTable &gt;&gt;= printTable

标签: haskell io


【解决方案1】:

只需使用您的printTable inside do-block 来处理readTable 产生的字符串:

readTable = do
  s <- readFile "projekt-board.txt"
  let content = lines s
  let removeEnd = init(content)
  let removeHead = tail(removeEnd)
  printTable removeHead

你无法从 IO monad do-block 中获得纯值,进入纯 Haskell 世界;但你不需要。

IO do-block 中的每一行必须具有相同的类型,IO a -- a 当然可能会有所不同,但必须是相同的格式 IO ado 块中最后一行的类型是整个do 块的类型。例如,

 #> :t putStr ""
putStr "" :: IO ()

所以,

printTable            :: String -> IO ()
           removeHead :: String
printTable removeHead ::           IO ()

适合。

【讨论】:

  • 添加一些关于当输入文件的行数太少时会发生什么的注释?
  • 我想要实现的是操作我从文件中收集的数据,所以 readTable 函数只是用来将表格读入列表,而 printTable 将是一个打印变化。现在假设表包含元素 [1,2,3] 并且我想将其更改为 [3,2,1] (稍后再做其他具有不同功能的东西)然后打印出来(而不是这样做在 readTable 函数中)。这种类型的操作可能吗?
  • @Banana 所以有一个函数changeTable :: String -&gt; String 并在你的do 块中调用它,比如...; let s2 = changeTable removeHead ; printTable s2
  • 好的,所以我理解的所有动作基本上都必须发生在 readTable 函数中?如果我使用用户操作执行任何其他 I/O,也必须从那里调用它?
  • do 块内。您可以拥有readTable :: IO String,然后在另一个do 块中使用它作为do { ... ; s &lt;- readTable ; let s2 = trasnformTable s ; print s2 }
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-03-01
  • 2012-06-26
  • 2013-09-13
  • 1970-01-01
  • 2017-06-07
  • 2015-09-02
  • 2012-09-27
相关资源
最近更新 更多