7

我正在阅读使用以下示例的教程(我将对其进行概括):

f :: Foo -> (Int, Foo)
...
fList :: Foo -> [Int]
fList foo = x : fList bar
  where
    (x, bar) = f foo

我的问题在于,您似乎可以在获取它们的元组之外按名称引用xand 。bar如果我的猜测是正确的,这似乎就像在其他语言中解构参数列表一样。(换句话说,我不必执行以下操作:)

fList foo = (fst tuple) : fList (snd tuple)
      where
        tuple = f foo

我对这种行为是否正确?我从未在我一直在阅读的教程/书籍中看到它。有人可以指出有关该主题的更多信息吗?

编辑:可以以类似的方式解构任何东西(列表、数组等),还是只能用元组来解构?

4

4 回答 4

14

看到您的编辑,我认为您要问的是Pattern matching

并回答您的问题:是的,您可以构造任何东西,您也可以使用构造函数“解构”。例如,您可能熟悉这种形式的模式匹配:

head :: [a] -> a
head (x:xs) = x
head []     = error "Can't take head of empty list"

但是,还有更多可以使用模式匹配的地方,其他有效的符号是:

head xs = case xs of
              (y:ys) -> y
              []     -> error "Can't take head of empty list"

head xs = let (y:ys) = xs
          in y

head xs = y
  where
    (y:ys) = xs

请注意,最后两个示例与第一个示例有点不同,因为当您使用空列表调用它们时,它们会给出不同的错误消息。


尽管这些示例特定于列表,但您可以对其他数据类型执行相同操作,如下所示:

first :: (a, b) -> a
first tuple = x
  where
    (x, y) = tuple

second :: (a, b) -> b
second tuple = let (x, y) = tuple
               in y

fromJust :: Maybe a -> a
fromJust ma = x
  where
    (Just x) = ma

同样,如果您使用 调用最后一个函数,它也会崩溃Nothing

总结一下; 如果您可以使用构造函数(如列表、(:)元组或Maybe )创建某些东西,则可以使用相同的构造函数以多种方式进行模式匹配。[](,)NothingJust

于 2009-01-11T12:16:54.343 回答
2

我对这种行为是否正确?

是的。但是,这些名称仅存在于您定义它们的块中。在您的情况下,这意味着您的where子句应用于的逻辑单元,即内部的表达式fList

于 2009-01-10T23:31:49.583 回答
1

另一种看待它的方式是这样的代码

x where x = 3

大致相当于

let x = 3 in x
于 2009-01-11T01:25:53.657 回答
0

你是对的。在 where 子句中绑定的名称对 where 子句之前的完整声明是可见的。在您的情况下,这些名称是fand bar

(学习 Haskell 的难点之一是,在源代码中在定义这些变量的位置之前的位置中使用变量不仅是允许的,而且是常见的。)

阅读有关 where 子句的更多信息的地方是Haskell 98 报告或可在 中找到的许多优秀教程之一haskell.org

于 2009-01-11T01:12:38.193 回答