Haskell 哈斯克尔永远的理解

Haskell 哈斯克尔永远的理解,haskell,monads,Haskell,Monads,目标:获取一个字符串并在控制台中打印相同的内容,就像永远需要执行相同的操作一样 我提出了类似这样的想法,没有编译错误,但没有按预期工作 greet_buggy :: String -> IO () greet_buggy = forever $ putStrLn 问题是字符串未在控制台中打印任何内容 greet_buggy "something" 基于此,我尝试调试并更改了定义,如下所示。它工作得很好 greet :: IO () greet = forever $ putStrLn

目标:获取一个字符串并在控制台中打印相同的内容,就像永远需要执行相同的操作一样

我提出了类似这样的想法,没有编译错误,但没有按预期工作

greet_buggy :: String -> IO ()
greet_buggy = forever $ putStrLn
问题是字符串未在控制台中打印任何内容

greet_buggy "something"
基于此,我尝试调试并更改了定义,如下所示。它工作得很好

greet :: IO ()
greet = forever $ putStrLn "Hello"
有人能解释一下这是怎么回事吗?是否有可能实现同样的效果永远单独使用

编辑:多亏了@Daniel Wagner,找到了一个更相关的问题,尽管这个问题和我的不同,答案解释了关于永远的问题

有人能解释一下这是怎么回事吗

我们有

putStrLn :: String -> IO ()
顺便说一下,它是->字符串monad中的一个值。因此,

forever putStrLn :: (->) String b
其中b是普遍量化的,因此我们也不幸地

forever putStrLn :: (->) String (IO ())
将发布的代码进行类型检查

要理解->字符串monad中永远存在的内容,请回想一下:

m >>= g
=  -- definition of >>=
\x -> g (m x) x
因此

回到永远:回想一下它的定义

forever m = m >> forever m
forever m = forever m
它在->字符串monad中等同于递归定义

forever m = m >> forever m
forever m = forever m
导致一个无用的无限循环

有人能解释一下这是怎么回事吗

我们有

putStrLn :: String -> IO ()
顺便说一下,它是->字符串monad中的一个值。因此,

forever putStrLn :: (->) String b
其中b是普遍量化的,因此我们也不幸地

forever putStrLn :: (->) String (IO ())
将发布的代码进行类型检查

要理解->字符串monad中永远存在的内容,请回想一下:

m >>= g
=  -- definition of >>=
\x -> g (m x) x
因此

回到永远:回想一下它的定义

forever m = m >> forever m
forever m = forever m
它在->字符串monad中等同于递归定义

forever m = m >> forever m
forever m = forever m
造成一个无用的无限循环。

永远执行完全相同的IO操作,或者通常是一元操作。如果函数接受字符串作为输入,则forever将永远打印相同的字符串。相反,如果每次都要从用户处读取字符串,则必须在IO操作中包含该字符串

什么是一个简单的IO操作,它从用户那里读取一行,然后打印出来?将getLine和putStrLn组合在一起:

然后把这个动作传给永远:

或者,事实证明,前奏曲中已经有某种东西为你完成了这一切:我们所写的相当于:

cat :: IO ()
cat = interact id
forever执行完全相同的IO操作,或者通常反复执行一元操作。如果函数接受字符串作为输入,则forever将永远打印相同的字符串。相反,如果每次都要从用户处读取字符串,则必须在IO操作中包含该字符串

什么是一个简单的IO操作,它从用户那里读取一行,然后打印出来?将getLine和putStrLn组合在一起:

然后把这个动作传给永远:

或者,事实证明,前奏曲中已经有某种东西为你完成了这一切:我们所写的相当于:

cat :: IO ()
cat = interact id
哈雷·巴吉在另一辆单子上工作

永远采取一元的行动,并无限期地重复它。它可以这样定义:

forever a = let loop = a >> loop in loop
这也可以可视化为

forever a = a >> a >> a >> a >> ...  (infinitely many times)
事实上,永远是在应用上定义的,而不是单子;但现在这并不重要

所以永远的问候实际上是

putStrLn "Hello" >> putStrLn "Hello" >> putStrLn "Hello" >> ...
这不需要进一步解释

OTOH forever greet_四轮马车相当于

putStrLn >> putStrLn >> putStrLn >> ...
现在,由于->a是一个单子,>>是为任何两个合适类型的函数定义的,在这种情况下,f>>g的含义是。。。就是g!那么

( putStrLn >> putStrLn >> putStrLn >> ... ) "Hello"
就是获取>>链中的最后一个函数,并将其应用于Hello。当然,这里没有最后一个函数,所以这个函数会一直运行。

greet\u buggy正在另一个monad上工作

永远采取一元的行动,并无限期地重复它。它可以这样定义:

forever a = let loop = a >> loop in loop
这也可以可视化为

forever a = a >> a >> a >> a >> ...  (infinitely many times)
事实上,永远是在应用上定义的,而不是单子;但现在这并不重要

所以永远的问候实际上是

putStrLn "Hello" >> putStrLn "Hello" >> putStrLn "Hello" >> ...
这不需要进一步解释

OTOH forever greet_四轮马车相当于

putStrLn >> putStrLn >> putStrLn >> ...
现在,由于->a是一个单子,>>是为任何两个合适类型的函数定义的,在这种情况下,f>>g的含义是。。。就是g!那么

( putStrLn >> putStrLn >> putStrLn >> ... ) "Hello"

就是获取>>链中的最后一个函数,并将其应用于Hello。当然,这里没有最后一个函数,所以这个函数将永远运行。

请尝试永远运行。Putstrlntanks,像greet一样工作,但它仍然不能完全解决我的目标?我想接受字符串并打印它,然后再接受一个像forevertry greet_buggy=forever这样的字符串。Putstrlntanks,像greet一样工作,但它仍然不能完全解决我的目标?我想接受字符串并打印它,然后再接受一个像foreverso forever$putStrLn这样的字符串。有些东西将始终打印相同的IO操作,即打印一些东西,如果我想将某些东西更改为介于两者之间的任何东西,我可以使用forever吗?我不确定我是否理解:您可能正在寻找像forever do这样的东西
是的,你的解释和这个评论解决了我的问题。Thankso forever$putStrLn某物将始终打印相同的IO操作,即打印某物,如果我想将某物更改为介于两者之间的任何内容,我可以使用forever执行此操作吗?我不确定我是否理解:您可能正在寻找类似forever do的内容是的,您的解释和此注释解决了我的问题。谢谢