3

当类型X定义为:

data X = 
    X { sVal :: String } |
    I { iVal :: Int } |
    B { bVal :: Bool }

我想要Int一个X值,如果有的话,否则为零。

returnInt :: X -> Int

如何确定X参数的类型returnInt是什么?

4

4 回答 4

13

使用模式匹配。

returnInt :: X -> Int
returnInt (I x) = x
returnInt _     = 0
于 2009-12-07T17:22:58.337 回答
10

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]
于 2009-12-07T17:35:02.060 回答
4

给定这样的函数:

returnInt :: X -> Int
returnInt x = {- some integer -}

...的类型x总是X。您关心的是是否x使用X,IB类型构造函数。

使用模式匹配来区分:

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"
于 2009-12-07T17:26:26.863 回答
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上面定义的行为。奇怪的错误消息只是告诉您该函数不知道如何处理 SomeType 类型不匹配的成员(I x)

如果您使用更常见的语法定义您的类型:

data SomeType2 = X String | I Int | B Bool

然后你就失去了那些不错的记录功能。

错误消息终止程序的执行。这有时很烦人。如果您的功能需要更安全的行为,GBacon 的答案就是这样做的方法。了解Maybe a类型并使用它来处理这种需要返回一些值或什么都不返回的计算(试试这个:http ://en.wikibooks.org/wiki/Haskell/Hierarchical_libraries/Maybe )。

于 2009-12-09T14:31:50.073 回答