当前位置:  开发笔记 > 编程语言 > 正文

好的Haskell编码风格的if/else控制块?

如何解决《好的Haskell编码风格的if/else控制块?》经验,为你挑选了3个好方法。

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

关于Wikibooks教程使用的if/ elsecontrol块的编码风格,我有一点疑问.代码如下所示:

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!"

所以,我很想知道更常使用哪种编码风格 - 或者这段代码是否有其他编码风格?



1> Greg Bacon..:

Haskell风格是功能性的,而不是必要的!而不是"做那么,"想想组合功能和描述什么程序会做,而不是如何.

在游戏中,您的程序会要求用户猜测.正确的猜测是赢家.否则,用户再次尝试.游戏一直持续到用户猜对了,所以我们写道:

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

这使用一个重复运行一个动作的组合器(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

在玩家正确猜测之前要运行的动作是

read `liftM` getLine

为什么不保持简单,只是组成这两个功能?

*Main> :type read . getLine

:1:7:
    Couldn't match expected type `a -> String'
           against inferred type `IO String'
    In the second argument of `(.)', namely `getLine'
    In the expression: read . getLine

类型getLineIO String,但read想要纯粹String.

liftMControl.Monad中的函数采用纯函数并将其"提升"为monad.表达式的类型告诉我们它的作用很多:

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

这是一个I/O操作,在运行时会给我们一个转换后的值read,Int在我们的例子中.回想一下,这readLine是一个产生String值的I/O操作,所以你可以认为liftM允许我们readIOmonad中" 应用" .

游戏示例:

1
Too low!
100
Too high!
42
You Win!


很好地使用组合器.我会更进一步写'untilM(isCorrect 42)(读<$> getLine)'和'True $> putStrLn"你赢了!".

2> mattiast..:

你可以使用"case"--construct:

doGuessing num = do
    putStrLn "Enter your guess:"
    guess <- getLine
    case (read guess) of
        g | g < num -> do 
            putStrLn "Too low!"
            doGuessing num
        g | g > num -> do 
            putStrLn "Too high!"
            doGuessing num
        otherwise -> do 
            putStrLn "You Win!"



3> Peter Burns..:

对mattiast的case语句的一个小改进(我编辑,但我缺乏业力)是使用compare函数,它返回三个值之一,LT,GT或EQ:

doGuessing num = do
   putStrLn "Enter your guess:"
   guess <- getLine
   case (read guess) `compare` num of
     LT -> do putStrLn "Too low!"
              doGuessing num
     GT -> do putStrLn "Too high!"
              doGuessing num
     EQ -> putStrLn "You Win!"

我真的很喜欢这些Haskell问题,我鼓励其他人发帖.通常你觉得有要表达你在想什么更好的办法,但Haskell是最初如此陌生,没有什么会浮现在脑海中.

Haskell journyman的奖金问题:doGuessing的类型是什么?

推荐阅读
N个小灰流_701
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有