在Haskell代数数据类型中选择备选方案

Chr*_*non 3 haskell types algebraic-data-types data-structures

当类型X定义为:

data X = 
    X { sVal :: String } |
    I { iVal :: Int } |
    B { bVal :: Bool }
Run Code Online (Sandbox Code Playgroud)

我希望Int里面有一个X值,如果有的话,否则为零.

returnInt :: X -> Int
Run Code Online (Sandbox Code Playgroud)

如何确定X参数的类型returnInt

Cat*_*lus 13

使用模式匹配.

returnInt :: X -> Int
returnInt (I x) = x
returnInt _     = 0
Run Code Online (Sandbox Code Playgroud)


Gre*_*con 10

对所有可能的X值使用更灵活的定义:

returnInt :: X -> Maybe Int
returnInt (I i) = Just i
returnInt _ = Nothing
Run Code Online (Sandbox Code Playgroud)

然后你可以使用maybe你想要的特定默认值-0可能是一个有效值(这被称为半无差别问题):

*Main> maybe 0 id (returnInt $ X "")
0
*Main> maybe 0 id (returnInt $ I 123)
123
*Main> maybe (-1) id (returnInt $ X "yo")
-1
Run Code Online (Sandbox Code Playgroud)

相反,部分函数存在运行时异常风险:

*Main> let returnInt (I i) = i
*Main> :t returnInt
returnInt :: X -> Int
*Main> returnInt (B True)
*** Exception: <interactive>:1:4-22: Non-exhaustive patterns in function returnInt
Run Code Online (Sandbox Code Playgroud)

如果你感觉真的很蛙,你可以使用 MonadPlus

returnInt :: (MonadPlus m) => X -> m Int
returnInt (I i) = return i
returnInt _ = mzero
Run Code Online (Sandbox Code Playgroud)

获得更大的灵活性:

*Main> maybe 0 id (returnInt $ X "")
0
*Main> maybe 0 id (returnInt $ I 123)
123
*Main> returnInt (I 123) `mplus` returnInt (I 456) :: [Int]
[123,456]
Run Code Online (Sandbox Code Playgroud)