gpt4 book ai didi

haskell - if/else 控制 block 的良好 Haskell 编码风格?

转载 作者:行者123 更新时间:2023-12-03 09:06:26 25 4
gpt4 key购买 nike

我正在学习 Haskell,希望它能帮助我更接近函数式编程。以前,我主要使用具有类 C 语法的语言,如 C、Java 和 D。

我对 if 的编码风格有一点疑问/else tutorial on Wikibooks 使用的控制 block .代码如下所示:

doGuessing num = do
putStrLn "Enter your guess:"
guess <- getLine
if (read guess) < num
then do putStrLn "Too low!"
doGuessing num
else if (read guess) > num
then do putStrLn "Too high!"
doGuessing num
else do putStrLn "You Win!"

这让我很困惑,因为这种编码风格完全违反了类 C 语言中推荐的风格,我们应该缩进 if , else if , 和 else在同一列。

我知道它在 Haskell 中不起作用,因为如果我缩进 else 将是一个解析错误与 if 在同一列.

但是下面的风格呢?我认为它比上面的要清楚得多。但是由于上面的内容被 Wikibooks 和 Yet Another Haskell Tutorial 使用,在 Haskell 官方网站上被标记为“最佳在线教程”,我不确定这种编码风格是否是 Haskell 程序中的约定。
doGuessing num = do
putStrLn "Enter your guess:"
guess <- getLine
if (read guess) < num then
do
putStrLn "Too low!"
doGuessing num
else if (read guess) > num then do
putStrLn "Too high!"
doGuessing num
else do
putStrLn "You Win!"

所以,我很好奇哪种编码风格更常用——或者这段代码是否还有另一种编码风格?

最佳答案

Haskell 风格是功能性的,而不是强制性的!与其“做这个然后那个”,不如考虑组合函数并描述你的程序将做什么,而不是如何做。

在游戏中,您的程序要求用户猜测。一个正确的猜测是赢家。否则,用户重试。游戏一直持续到用户猜对为止,所以我们这样写:

main = untilM (isCorrect 42) (read `liftM` getLine)

这使用了一个重复运行 Action 的组合器( getLine 拉取一行输入, read 在这种情况下将该字符串转换为整数)并检查其结果:
untilM :: Monad m => (a -> m Bool) -> m a -> m ()
untilM p a = do
x <- a
done <- p x
if done
then return ()
else untilM p a

谓词(部分应用于 main )根据正确值检查猜测并做出相应响应:
isCorrect :: Int -> Int -> IO Bool
isCorrect num guess =
case compare num guess of
EQ -> putStrLn "You Win!" >> return True
LT -> putStrLn "Too high!" >> return False
GT -> putStrLn "Too low!" >> return False

在玩家猜对之前要运行的 Action 是
read `liftM` getLine

为什么不保持简单,只组合这两个函数呢?

*Main> :类型读取。获取线

<交互式>:1:7:
无法匹配预期的类型 `a -> String'
针对推断类型“IO String”
在 `(.)' 的第二个参数中,即 `getLine'
在表达式中: read 。获取线
getLine的类型是 IO String , 但是 read想要一个纯粹的 String .

函数 liftM 从 Control.Monad 获取一个纯函数并将其“提升”为一个 monad。表达式的类型告诉我们很多关于它的作用:

*Main> :type read `liftM` getLine
读取 `liftM` getLine::(Read a) => IO a

这是一个 I/O 操作,运行时会返回一个用 read 转换的值。 , 一个 Int在我们的例子中。回想一下 readLine是产生 String 的 I/O 操作值,所以你可以想到 liftM允许我们申请 read “内部” IO单子(monad)。

示例游戏:

1
太低!
100
太高!
42
你赢了!

关于haskell - if/else 控制 block 的良好 Haskell 编码风格?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/127190/

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