0

在与现实世界 haskell的第 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不被视为函数声明之前定义的全局变量。它们是局部变量。我认为如果没有与全局变量同名的局部变量,则全局变量不会隐藏。

4

3 回答 3

4

这里的主要内容是模式匹配中的变量总是引入新变量而不是引用现有变量。您的问题与全局变量和局部变量无关。

如果您想将 的值与模式f中的某个变量的值相匹配,则apple需要使用模式保护和相等测试。例如

whichFruit f
    | f == apple  = Apple
    | f == orange = Orange
于 2014-05-17T10:54:56.373 回答
1

正确的。但是这里有一个apple与全局变量同名的局部变量apple,即apple(duh)。

模式的关键在于它们不会比较变量而是寻找特定的区别特征,同时将所有其他信息重新打包到新变量中。“显着特征”是构造函数匹配(总是大写1),它们不会出现在 中case f of { apple -> ... },因此所有信息都在变量中传递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 (:)(它们都以冒号开头,就像所有命名构造函数都以大写字母开头一样)。

于 2014-05-17T09:28:13.307 回答
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

这里的变量appleorange是无可辩驳的模式。它们没有引用您已经创建的全局函数。实际上,您可以删除 and 的全局定义appleorange编译它们以获得一个想法。无论您提供什么输入,您总是会得到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
于 2014-05-17T09:53:26.847 回答