Haskell - 在`do`块

时间:2016-10-23 08:46:22

标签: haskell monads

我有一个小的Haskell程序,其行为需要根据提供的参数数量略有不同。我不知道如何根据提供的参数数量以一种简洁的方式分配三个变量。

我希望在其他编程语言中使用类似case表达式或等效switch的内容,但无法解决问题。

这是我当前(错误的)代码,它依赖于Dice.Base模块生成随机数:

{-# LANGUAGE ScopedTypeVariables #-}
import Dice.Base
import System.Environment
import Data.List

main :: IO()

--Expected argument formats:
--(number of dice, number of faces on each die, number to add to total)
--(number of dice, number of faces on each die) 
--(number of faces on a single die)
main = do
        args  <- getArgs

        --Set the number of dice, number of faces on each die,
          --and number to add to sum of rolls.
        case (length args) of
          3 ->   let (numDice ::NaturalP) = toNaturalP $ read $ args!!0;
                 let (numFaces::NaturalP) = toNaturalP $ read $ args!!1;
                 let (offset  ::Integer ) = read $ args!!2;
          2 ->   let (numDice ::NaturalP) = toNaturalP $ read $ args!!0;
                 let (numFaces::NaturalP) = toNaturalP $ read $ args!!1;
                 let (offset  ::Integer ) = 0;
          1 ->   let (numDice ::NaturalP) = 1;
                 let (numFaces::NaturalP) = toNaturalP $ read $ args!!0;
                 let (offset  ::Integer ) = 0;

        -- 'dc' is a structure capturing the Dice Configuration.
        let dc = NumSidesPlus numDice numFaces offset
        outcomeInteger <- roll dc

        putStrLn("Dice configuration:     " ++ (show dc))
        putStrLn("Outcome:                " ++ (show outcomeInteger))

当然,这不起作用,因为case会产生一个表达;它不是设计用于do块。

我知道可以let (a,b,c) = case ...并将这三个值分配为元组,但我认为这是一种解决方法,因为它对于更复杂的项目并没有帮助我。 do块内的流量控制方法有哪些?在命令式语言中是否有类似于switch的东西?

如何完成此因变量赋值?

2 个答案:

答案 0 :(得分:4)

不是切换列表的长度然后索引,我宁愿直接在列表上进行模式匹配,同时也使用ViewPatterns

main :: IO ()
main = do 
    args  <- getArgs
    let (arg1,arg2) = case args of
                        [] -> (1::Int,"default")
                        [read -> arg1, read -> arg2] -> (arg1,arg2)
    print (arg1,arg2)    

如果元组不够,因为提取逻辑很复杂,我会定义一个包含可能替代方案的自定义数据类型。

您还可以使用guardsPatternGuards扩展名对每场比赛施加复杂条件。

答案 1 :(得分:2)

您需要将变量绑定到表达式并让表达式确定值,而不是假设您可以执行某些pathalogical变量声明:

let (numDice,numFaces,offset) =
     case (length args) of
      3 ->   (toNaturalP $ read $ args!!0
             ,toNaturalP $ read $ args!!1
             ,read $ args!!2)
      2 ->   (toNaturalP $ read $ args!!0
             ,toNaturalP $ read $ args!!1
             ,0)
      1 ->   (1
             ,toNaturalP $ read $ args!!0
             ,0)