Data structures 在Haskell代数数据类型中选择备选方案
当类型Data structures 在Haskell代数数据类型中选择备选方案,data-structures,haskell,types,algebraic-data-types,Data Structures,Haskell,Types,Algebraic Data Types,当类型X定义为: data X = X { sVal :: String } | I { iVal :: Int } | B { bVal :: Bool } 我想要Int在X值内,如果有,否则为零 returnInt :: X -> Int 如何确定returnInt的参数是哪种类型的X?使用模式匹配 returnInt :: X -> Int returnInt (I x) = x returnInt _ = 0 给定这样一个函数: ret
X
定义为:
data X =
X { sVal :: String } |
I { iVal :: Int } |
B { bVal :: Bool }
我想要Int
在X
值内,如果有,否则为零
returnInt :: X -> Int
如何确定returnInt
的参数是哪种类型的X
?使用模式匹配
returnInt :: X -> Int
returnInt (I x) = x
returnInt _ = 0
给定这样一个函数:
returnInt :: X -> Int
returnInt x = {- some integer -}
…x
的类型始终为x
。您关心的是x
是否使用x
、I
或B
类型构造函数
使用模式匹配来区分差异:
returnInt :: X -> Int
returnInt (X _) = error "needed an Int, got a String"
returnInt (I { iVal = n }) = n
returnInt (B _) = error "needed an Int, got a Bool"
对所有可能的
X
值使用更灵活的定义:
returnInt :: X -> Maybe Int
returnInt (I i) = Just i
returnInt _ = Nothing
然后,您可以使用所需的特定默认值-0可能是有效值(这称为):
相反,部分函数存在运行时异常的风险:
*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
要获得更大的灵活性:
*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]
为了澄清这里的一点,让我重写您的数据类型,以避免X的含义不明确:
data SomeType = X { myString :: String} | I {myInt :: Int} | B {myBool :: Bool}
在此定义中,没有X、I和B类型。十、 I和B是构造函数,它们创建类型为Sometype
的值。请注意,当您询问ghci使用这些类型构造函数构造的任何值的类型时会发生什么情况:
*Main> :t (I 5)
(I 5) :: Sometype
*Main> :t (B False)
(B False) :: Sometype
他们属于同一类型
正如您可以使用X、I和B来构造类型一样,您也可以使用模式匹配来解构类型,就像上面其他答案中所做的那样:
returnInt :: SomeType -> Int
returnInt (I x) = x -- if the pattern matches (I x) then return x
returnInt _ = error "I need an integer value, you moron" -- throw an error otherwise
请记住,模式匹配是按顺序进行的:如果值与某行中的模式匹配,则不会执行下面行中的模式
请注意,当您像以前一样定义类型时,使用所谓的记录语法(请看这里:),您可以免费获得这样的函数
尝试查看myInt的类型,例如:
*Main> :t myInt
myInt :: SomeType -> Int
看看这个函数的作用:
*Main> myInt (I 5)
5
*Main> myInt (B False)
*** Exception: No match in record selector Main.myInt
这正是上面定义的returnInt
的行为。奇怪的错误消息只是告诉您,函数不知道如何处理与(ix)
不匹配的SomeType类型的成员
如果使用更常见的语法定义类型:
data SomeType2 = X String | I Int | B Bool
然后你就失去了那些好的录音功能
错误消息终止程序的执行。这有时很烦人。如果您的功能需要更安全的行为,GBacon的答案就是这样做的。了解
可能是
类型,并使用它来处理这种需要返回某些值或不返回任何值的计算(请尝试此:)。要在内部添加一些内容,您的定义基本上是说类型X要么是类型构造函数X,要么是类型构造函数I,要么是类型构造函数B。您的函数接受X的任何成员,因此您可以只使用模式匹配I,它是X的成员。@codebliss:Minor nitpick:这三个都是数据构造函数。例如,类型构造函数是Maybe
,它有一种*->*
:对它应用一个类型,就得到了一个具体的类型。在上一个示例中,它的mzero
方法使用MonadPlus
。在最近设计库时,我遇到了这种情况,并决定使用return
和fail
在Monad
类中返回一个值比使用MonadPlus
更好。我知道fail
被一些人视为一个缺点,但我决定使用它是一个更好的推广,因为我们将使用MonadPlus
仅用于其mzero方法。你的想法是什么?@jberryman这取决于上下文。我通常倾向于使用更优雅的代码为库用户提供更好的抽象。你的问题会成为一个有趣的社区维基!
*Main> myInt (I 5)
5
*Main> myInt (B False)
*** Exception: No match in record selector Main.myInt
data SomeType2 = X String | I Int | B Bool