gpt4 book ai didi

haskell - 如何读取haskell字符串

转载 作者:行者123 更新时间:2023-12-02 02:50:51 26 4
gpt4 key购买 nike

我完全是 Haskell 的初学者,虽然熟悉 Python、F#、Java、C# 和 C++ 等语言的函数范式(以有限的方式)。

一直在逃避我的是haskell中的IO。我尝试了几次,甚至在尝试绕过它的过程中学习了 C# 和 F#。

更具体地说,我指的是在没有 do 表示法的情况下获得 IO,使用 do 表示法,IO 变得微不足道。这可能是不好的做法,但在业余时间,我喜欢看看我是否可以用一个连续的表情完成事情。尽管这是一种不好的做法,但它很有趣。

这样的表达式通常是这样的(在伪haskell中):

main = getStdinContentsAsString 
>>= ParseStringToDataStructureNeeded
>>= DoSomeComputations
>>= ConvertToString
>>= putStrLn

我对最后四个部分没有任何问题。我学习 F# 的原因之一是只是想看看除了 IO 之外是否有什么我没有想到的,但是一旦我有了方便的 F# Console.ReadLine() 它返回一个普通的旧字符串,它基本上就是一帆风顺。

这让我又回到了haskell,再次被IO机制阻止。

我已经设法(在这里使用另一个问题)从控制台读取 int,并打印“Hello World!”很多次
main = (readLn :: IO Int) >>= \n -> mapM_ putStrLn $ replicate n "Hello World!"

我想至少获得一些“通用”方式来读取标准输入的全部内容(可能是多行,所以 getContents 需要成为选择的函数)作为字符串,然后我可以使用处理字符串其他功能,如 unlines 和 map。

我已经尝试过的一些事情:

正如我所说, getContents 将是我需要的(除非有一些等价物)。

使用逻辑,因为
getContents :: IO String

然后我需要一些接受 IO 字符串并返回一个普通的旧字符串的东西。这是(据我所知)
unsafePerformIO :: IO a -> a

但是由于某种原因,ghc 并不高兴:
* Couldn't match type `[Char]' with `IO (IO b)'
Expected type: String -> IO b
Actual type: IO (IO b) -> IO b
* In the second argument of `(>>=)', namely `unsafePerformIO'
In the expression: getContents >>= unsafePerformIO

我尝试的另一件事:这没有问题;
main = getContents >>= putStrLn

即使 getContents 返回的类型是一个 IO 操作,而不是 putStrLn 想要的本身 String
getContents :: IO String
putStrLn :: String -> IO ()

不知何故, Action 被神奇地执行了,结果字符串被传递到 put 函数中。

但是当我尝试添加一些东西时,比如在打印之前简单地将“hello”附加到输入中:
main = getContents >>= (++ " hello") >>= putStrLn

我突然得到一个类型不匹配:
Couldn't match type `[]' with `IO'
Expected type: String -> IO Char
Actual type: [Char] -> [Char]
* In the second argument of `(>>=)', namely `(++ " hello")'
In the first argument of `(>>=)', namely
`getContents >>= (++ " hello")'
In the expression: getContents >>= (++ " hello") >>= putStrLn

不知何故,IO 操作不再执行(或者我只是不明白这一点)。

我也尝试了很多东西,组合 getLinereadLngetContentsunsafePerformIOreadfmap 无济于事。

这只是一个非常基本的例子,但它完美地说明了让我现在多次放弃 haskell 的问题(而且可能我不是唯一一个),尽管我很固执地想要了解它并了解什么是几乎函数式编程语言让我回来了。

总结:
  • 有什么我没有得到的吗?(99% 是)
  • 如果是,那是什么?
  • 我应该如何阅读整个标准输入并在一个连续的表达式中处理它?(如果我只需要 1 行,我想无论解决方案是什么,它也可以与 getLine 一起使用,因为它基本上是 getContents 的姐妹)

  • 提前致谢!

    最佳答案

    您没有考虑的主要事情似乎是 >>= 的类型:

    (>>=) :: IO a -> (a -> IO b) -> IO b

    换句话说,您不需要“解包” IO StringString ; >>=运算符(operator)已经递了一个普通的 String到它的右操作数(函数):
    getContents >>= (\s -> ...)
    -- ^ s :: String

    原因 getContents >>= (++ " hello")失败是 >>=要求函数返回 IO ...值,但 (++ "hello") :: String -> String .

    您可以通过添加 return :: a -> IO a 来解决此问题混合:
    getContents >>= (return . (++ "hello"))

    整个表达式的类型为 IO String .执行时,它将从 stdin 读取数据, 附加 "hello"给它,并返回结果字符串。

    因此,
    getContents >>= (return . (++ "hello")) >>= putStrLn

    应该可以正常工作。但这比必要的复杂。从概念上讲, returnIO 中包装一个值和 >>=再次打开它(有点)。

    我们可以融合 return/ >>=右边的位:
    getContents >>= (\s -> putStrLn (s ++ "hello"))

    IE。而不是服用 getContents :: IO String , 添加 "hello"到它形成一个新的 IO String操作,然后附加 putStrLn :: String -> IO ()对它,我们包裹 putStrLn创建一个新的 String -> IO ()函数(在将事物交给 "hello" 之前将 putStrLn 附加到其参数中)。

    现在,如果我们愿意,我们可以摆脱 s通过标准的无积分技巧:
    getContents >>= (putStrLn . (++ "hello"))

    关于 IO 的说明一般来说:要记住的是 IO ...是普通的 Haskell 类型。这里没有魔法发生。 >>=不执行任何 Action ;它只是结合了 IO something 类型的值以及构造 IO somethingelse 类型的新值的函数.

    您可以将 Haskell 视为一种纯粹的元语言,它将命令式程序(即要执行的指令列表)构造为内存中的数据结构。唯一实际执行的是绑定(bind)到 Main.main 的值。 .也就是说,它就像一个命令式运行时运行您的 Haskell 代码以在 main :: IO () 中生成一个纯值。 .然后这个值的内容作为命令式指令执行:
    main :: IO ()
    main =
    putChar 'H' >>
    putChar 'i' >>
    putChar '\n'
    main绑定(bind)到表示命令式程序的数据结构 print 'H'; print 'i'; print newline .运行 Haskell 程序会构建这个数据结构,然后运行时执行它。

    然而,这个模型并不完整:命令式运行时可以回调到 Haskell 代码中。 >>=可用于在命令式代码中“嵌入” Haskell 函数,然后可以(在运行时)检查值、决定下一步做什么等。但所有这些都以纯 Haskell 代码的形式发生;只有 IOf 返回的值在 x >>= f很重要( f 本身没有副作用)。

    关于haskell - 如何读取haskell字符串,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47115255/

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com