当类型X
定义为:
data X =
X { sVal :: String } |
I { iVal :: Int } |
B { bVal :: Bool }
我希望Int
位于X
值内(如果有),否则为零。
returnInt :: X -> Int
如何确定X
的参数returnInt
的类型是什么?
答案 0 :(得分:13)
使用模式匹配。
returnInt :: X -> Int
returnInt (I x) = x
returnInt _ = 0
答案 1 :(得分:10)
对所有可能的X
值使用更灵活的定义:
returnInt :: X -> Maybe Int
returnInt (I i) = Just i
returnInt _ = Nothing
然后你可以使用maybe
来表示你想要的特定默认值 - 0可能是一个有效值(这被称为semipredicate problem):
*Main> maybe 0 id (returnInt $ X "")
0
*Main> maybe 0 id (returnInt $ I 123)
123
*Main> maybe (-1) id (returnInt $ X "yo")
-1
相反,部分函数存在运行时异常风险:
*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
如果你感觉真的很胖,你可以使用MonadPlus
returnInt :: (MonadPlus m) => X -> m Int
returnInt (I i) = return i
returnInt _ = mzero
获得更大的灵活性:
*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]
答案 2 :(得分:4)
给定这样的函数:
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"
答案 3 :(得分:3)
为了澄清这里的一点,让我重写你的数据类型,以避免X的含义含糊不清:
data SomeType = X { myString :: String} | I {myInt :: Int} | B {myBool :: Bool}
在此定义中,没有X,I和B类型。 X,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
请记住,模式匹配按顺序发生:如果值与某些行中的模式匹配,则下面行中的模式将不会被执行。
请注意,当您像使用所谓的记录语法一样定义类型时(只需查看此处:http://en.wikibooks.org/wiki/Haskell/More_on_datatypes),您可以免费获得类似的功能!!
尝试查看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
的行为。奇怪的错误消息只是告诉您该函数不知道如何处理与(I x)
不匹配的SomeType类型的成员。
如果使用更常见的语法定义类型:
data SomeType2 = X String | I Int | B Bool
然后你放松了那些不错的记录功能。
错误消息终止程序的执行。这有时很烦人。如果您的功能需要更安全的行为,那么GBacon的答案就是实现它的方法。了解Maybe a
类型并使用它来处理需要返回某些值或不返回任何值的此类计算(请尝试:http://en.wikibooks.org/wiki/Haskell/Hierarchical_libraries/Maybe)。