在真实世界haskell 的chapter 3部分与变量错误匹配的部分中,有一个示例如下:
-- file: ch03/BogusPattern.hs
data Fruit = Apple | Orange
apple = "apple"
orange = "orange"
whichFruit :: String -> Fruit
whichFruit f = case f of
apple -> Apple
orange -> Orange
解释说明在case f of
部分,apple
和orange
不被视为函数声明之前定义的全局变量。它们是局部变量。我想如果没有局部变量拥有与全局变量相同的名称,则不会隐藏全局变量。
答案 0 :(得分:4)
这里的主要内容是模式匹配中的变量总是引入新变量而不是引用现有变量。您的问题与全局变量和局部变量无关。
如果要在模式中将f
的值与某个变量(如apple
的值)匹配,则需要使用模式保护和相等性测试。 E.g。
whichFruit f
| f == apple = Apple
| f == orange = Orange
答案 1 :(得分:1)
右。但是这里有一个局部变量apple
拥有与全局变量apple
相同的名称,即apple
(duh)。
关于模式的关键之处在于它们并没有像寻找特定的区别特征那样比较变量,同时将所有其他信息重新打包成新变量。 “区别特征”是构造函数匹配(总是大写 1 ),它们不会出现在case f of { apple -> ... }
中,所以只需 all 就可以在变量apple
。
data Vegetable = Tomato | Potato
data Edible = Fruit Fruit | Vegetable Vegetable
如果您希望函数采用Edible
参数,则解构类型通常很有用。这可能是这样的:
canJuice :: Edible -> Bool
canJuice (Fruit Apple) = False
canJuice (Fruit Orange) = True
canJuice (Vegetable Tomato) = True
canJuice (Vegetable Potato) = False
现在,对于更复杂的数据,编写这么多canJuice
子句很尴尬。另一种方法是首先只匹配最外面的构造函数,然后将其他工作委托给别处:
canJuice :: Edible -> Bool
canJuice (Fruit fruit) = fruitJuicy fruit
canJuice (Vegetable veg) = vegetableJuicy veg
vegetableJuicy :: Vegetable -> Bool
vegetableJuicy Tomato = True
vegetableJuicy Potato = False
为了实现这一点,我们需要Haskell的特性,即将模式中出现的任何小写名称视为一个新变量,它接受模式匹配的“洞”中的值。
1 还有中缀构造函数,最着名的是list-cons (:)
(它们都以冒号开头,就像所有命名的构造函数都以大写字母开头一样)。
答案 2 :(得分:1)
你已经遇到了irrefutable patterns
。正如本书所提到的,普通变量名称和通配符_
是无可辩驳模式的示例。另一个将更清楚地展示irrefutable patterns
的例子:
data Fruit = Apple | Orange deriving (Show)
patternMatch f = case f of
something -> Apple
现在上面的程序有一个警告。在ghci:
ghci> patternMatch 2
Apple
ghci> patternMatch "hi"
Apple
所以基本上变量something
是一个与任何东西匹配的无可辩驳的模式。
现在,回到你的例子:
whichFruit :: String -> Fruit
whichFruit f = case f of
apple -> Apple
orange -> Orange
此处变量apple
和orange
是无可辩驳的模式。它们不引用您已创建的全局函数。实际上,您可以删除apple
和orange
的全局定义并编译它们以获得一个想法。无论你给出什么输入,你都会得到Apple
作为上述代码的答案(因为它是一个无可辩驳的模式):
ghci > whichFruit "apple"
Apple
ghci > whichFruit "orange"
Apple
ghci > whichFruit "pineApple"
Apple
如何在Haskell中的函数中使用全局变量?
实际上这很容易。只需在函数定义中使用它们即可。
data Fruit = Apple | Orange deriving (Show)
apple = "apple"
orange = "orange"
giveFruit :: Fruit -> String
giveFruit Apple = apple
giveFruit Orange = orange
在ghci:
ghci> giveFruit Apple
"apple"
ghci> giveFruit Orange
"orange"
在函数定义中使用变量是直截了当的。
如果我希望变量引用全局,应该怎么做 拥有相同名称的变量?
一种方法是使用整个模块名称来引用它。例如:
module Fruit where
data Fruit = Apple | Orange deriving (Show)
apple = "apple"
orange = "orange"
giveFruit2 :: Fruit -> String
giveFruit2 apple = Fruit.apple