好的Haskell编码风格的if / else控制块? [英] Good Haskell coding style of if/else control block?

查看:987
本文介绍了好的Haskell编码风格的if / else控制块?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在学习Haskell希望它能让我更接近函数式编程,在开始之前,我大多使用C-sytanx喜欢的语言,如C,Java或D编程语言。



我按照 Wikibook上的教学,到目前为止,我可以在简单输入和输出一章之前了解它们大多数



但我有一个关于if / else控制块使用的编码风格的问题教程。



在wikibook中,代码如下所示:

  doGuessing num = do 
putStrLn输入您的猜测:
guess< - getLine
if(read guess)< num
然后做putStrLn太低了!
doGuessing num
else if(read guess)> num
然后做putStrLn太高了!
doGuessing num
else do putStrLn你赢了!

这让我很困惑,因为这种编码风格是完全volate好编码风格在C-sytnax像编程语言,我们应该在同一列中识别if / else if / else。



我知道它在Haskell中不起作用,因为它会导致解析错误在if的同一列中标识else。



但是下面的一个呢?我认为它比上面的更清楚。但是由于上面是由Wikibook和Yet Another Haskell教程使用的,它在Haskell官方网站上标记了最好的在线教程,所以我不知道这种编码风格是否是Haskell程序中的约定。

  doGuessing num = do 
putStrLn输入您的猜测:
guess< - getLine
if )& num then
do
putStrLn太低了!
doGuessing num
else if(read guess)> num then do
putStrLn太高了!
doGuessing num
else do
putStrLn你赢了!

所以,我很想知道哪种编码风格被更频繁地使用或者是否有anthoer编码风格这段代码?我想知道它。

解决方案

Haskell风格是功能,而不是命令!



在游戏中,您可以使用你的程序要求用户猜测。正确的猜测是赢家。否则,用户再次尝试。游戏继续直到用户正确猜测,所以我们写:

  main = untilM(isCorrect 42)这使用一个组合器,它重复运行一个动作( getLine   code>拉一行输入,并且 read 在这种情况下将该字符串转换为整数)并检查其结果:

  untilM :: Monad m => (a→m Bool)→ m a  - > m()
untilM pa = do
x< - a
done< - px
如果完成
then return()
else untilM pa

谓语(部分应用于 main )对正确值的猜测,并相应地响应:

  isCorrect :: Int  - Int  - > IO Bool 
isCorrect num guess =
case比较num猜猜
EQ - > putStrLn你赢了! >> return True
LT - > putStrLn太高了! >> return False
GT - > putStrLn太低了! >> return False

要执行的操作,直到玩家正确猜测为

 阅读`liftM` getLine 

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

 * Main>:类型读。 getLine 

< interactive::1:7:
不能匹配预期类型`a - > String'
对于推断类型`IO String'
`(。)'的第二个参数,即`getLine'
在表达式中:read。 getLine

getLine 的类型是 IO String ,但需要一个纯 String



liftM 从Control.Monad采取一个纯粹的功能,并提升到一个monad。表达式的类型告诉我们它做了什么:

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

这是一个I / O操作,当运行时给我们一个转换值 read Int 。回想一下, readLine 是产生 String 值的I / O操作,因此您可以认为 liftM 允许我们在 IO monad中应用 p>

示例游戏:

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


I'm learning Haskell hope it could let me getting closer to functional programming, before learing it, I mostly use C-sytanx like languages, like C, Java or D Programming Language.

I followed the tutorial on Wikibook, it goes well so far, I could understand most of them before the chapter "Simple input and output"

But I do have a little question about the coding style of if/else control block used by the tutorial.

In the wikibook, the code look like the following:

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

It makes me confusing, because this coding style is totally volate "Good Coding Style" in C-sytnax like programming language, where we should ident if/else if/else at same column.

I know it just not work in Haskell, because it would cause parse error if I ident "else" at same column of "if".

But what about the following one? I think it is much more clear then the above one. But since the above is used by Wikibook and Yet Another Haskell Tutorial, which marked "best tutorial available online" at offical Haskell website, so I'm not sure whether this coding style is a convention in Haskell programs.

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

So, I'm curious about which coding style is used more often or is there anthoer coding style for this piece of code? I would like to know it too.

解决方案

Haskell style is functional, not imperative! Rather than "do this then that," think about combining functions and describing what your program will do, not how.

In the game, your program asks the user for a guess. A correct guess is a winner. Otherwise, the user tries again. The game continues until the user guesses correctly, so we write that:

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

This uses a combinator that repeatedly runs an action (getLine pulls a line of input and read converts that string to an integer in this case) and checks its result:

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

The predicate (partially applied in main) checks the guess against the correct value and responds accordingly:

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

The action to be run until the player guesses correctly is

read `liftM` getLine

Why not keep it simple and just compose the two functions?

*Main> :type read . getLine

<interactive>: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

The type of getLine is IO String, but read wants a pure String.

The function liftM from Control.Monad takes a pure function and "lifts" it into a monad. The type of the expression tells us a great deal about what it does:

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

It's an I/O action that when run gives us back a value converted with read, an Int in our case. Recall that readLine is an I/O action that yields String values, so you can think of liftM as allowing us to apply read "inside" the IO monad.

Sample game:

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

这篇关于好的Haskell编码风格的if / else控制块?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆