在GHCi中工作>但是在加载时没有?

use*_*127 0 haskell

我无法弄清楚为什么我得到两个不同的结果,但我确定它与IO我有所关系,我开始讨厌!

例如:

  ghci> x <- readFile "foo.txt"
  ghci> let y = read x :: [Int]
  ghci> :t y
  y :: [Int]
Run Code Online (Sandbox Code Playgroud)

现在,当我创建该文件并执行相同的操作时,它出现了IO [Int]吗?

foo.txt 是一个仅包含以下内容的txt文件: 12345

有人可以向我解释一下吗?因为我要抢购它!

感谢您的任何见解!

Sat*_*vik 6

阅读关于ghci.报价

在GHCi提示符下接受的语句的语法与Haskell do表达式中的语句的语法完全相同.但是,这里没有monad重载:在提示符下键入的语句必须在IO monad中.

IO当你在ghci写任何东西时,基本上你都在Monad 里面.


And*_*ewC 5

大意

清楚Haskell在IO产生值的操作和值本身之间的区别.

推荐阅读

在Haskell中对IO的一个很好的参考,不希望你想知道monad的理论基础是sigfpe的 IO Monad对于那些根本不关心的人.

请注意,这是他假设你不关心的monad理论位.他假设你关心做IO.这不是很长,而且我认为这对你来说非常值得一读,因为它明确了一些你不知道的"规则",因此引起了你的不满.

你的代码

无论如何,在你的代码中

x <- readFile "foo.txt"
Run Code Online (Sandbox Code Playgroud)

readFile "foo.txt"位具有类型IO String,这意味着它是一个产生String的操作.执行此操作时x <- readFile "foo.txt",您将使用它x来引用它生成的String.注意输出x和产生它的操作之间的区别readFile "foo.txt".

接下来让我们来看看y.您可以定义let y = read x :: [Int],所以y是INTS的列表,如您指定.但是,y与定义它的整个块不同.

example = do
  x <- readFile "foo.txt"
  let y = read x :: [Int]
  return y
Run Code Online (Sandbox Code Playgroud)

在这里example :: IO [Int],虽然y它本身有类型[Int].

你沮丧的原因

如果你来自命令式语言,这一开始就令人沮丧 - 你已经习惯了能够使用在你使用值的任何地方产生值的函数,但是你已经习惯了那些允许执行任意IO操作的函数.

在Haskell中,您可以使用"纯"函数(不使用IO)而不是IO操作来执行任何您喜欢的操作.Haskell程序员看到返回值的IO操作和只能在其他任何地方使用的纯函数之间存在差异.

这意味着您最终可能会陷入笨拙的IO monad中,并且您的所有函数都充满了IO数据类型.这很不方便你编写凌乱的代码.

如何避免IO混乱

首先在使用外部(文件或用户)数据的情况下完全解决您的问题:

  • 将通常从文件或用户读取的样本数据写为源代码中的值.
  • 使用定义中所需的任何数据将函数编写为函数的参数.这是在编写纯代码时获取数据的唯一方法.首先编写纯代码.
  • 在样本数据上测试您的功能.(如果您愿意,每次编写新函数时都可以重新加载ghci,确保它符合您的预期.)
  • 一旦程序在没有IO的情况下完成,您可以将其作为最终纯代码的包装器引入.

这意味着在你的程序中,我认为你不应该写任何readFile或其他IO代码,直到你差不多完成.

这是一个完全不同的工作流程 - 在命令式语言中,您可以编写代码来读取数据,然后执行操作,然后编写数据.在Haskell中,最好先编写完成内容的代码,然后在知道功能正确后再编写代码来读取和写入数据.