当类型X
定义为:
data X =
X { sVal :: String } |
I { iVal :: Int } |
B { bVal :: Bool }
我想要Int
一个X
值,如果有的话,否则为零。
returnInt :: X -> Int
如何确定X
参数的类型returnInt
是什么?
当类型X
定义为:
data X =
X { sVal :: String } |
I { iVal :: Int } |
B { bVal :: Bool }
我想要Int
一个X
值,如果有的话,否则为零。
returnInt :: X -> Int
如何确定X
参数的类型returnInt
是什么?
使用模式匹配。
returnInt :: X -> Int
returnInt (I x) = x
returnInt _ = 0
X
对所有可能的值使用更灵活的定义:
returnInt :: X -> Maybe Int
returnInt (I i) = Just i
returnInt _ = Nothing
然后你可以使用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
相反,部分函数有运行时异常的风险:
*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]
给定这样的函数:
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 的含义产生歧义:
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
上面定义的行为。奇怪的错误消息只是告诉您该函数不知道如何处理 SomeType 类型不匹配的成员(I x)
。
如果您使用更常见的语法定义您的类型:
data SomeType2 = X String | I Int | B Bool
然后你就失去了那些不错的记录功能。
错误消息终止程序的执行。这有时很烦人。如果您的功能需要更安全的行为,GBacon 的答案就是这样做的方法。了解Maybe a
类型并使用它来处理这种需要返回一些值或什么都不返回的计算(试试这个:http ://en.wikibooks.org/wiki/Haskell/Hierarchical_libraries/Maybe )。