在Haskell中解构元组时,元素可以在哪里使用?

时间:2022-12-22 22:30:31

I am reading a tutorial that uses the following example (that I'll generalize somewhat):

我正在阅读一个使用以下示例的教程(我将稍微概括一下):

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

My question lies in the fact that it seems you can refer to x and bar, by name, outside of the tuple where they are obtained. This would seem to act like destructuring parameter lists in other languages, if my guess is correct. (In other words, I didn't have to do the following:)

我的问题在于,似乎你可以通过名称引用x和bar,在元组之外获取它们。如果我的猜测是正确的话,这似乎就像在其他语言中解构参数列表一样。 (换句话说,我没有做以下:)

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

Am I right about this behavior? I've never seen it mentioned yet in the tutorials/books I've been reading. Can someone point me to more info on the subject?

我对这种行为是对的吗?在我读过的教程/书籍中,我从未见过它。有人能指出我有关这个问题的更多信息吗?

Edit: Can anything (lists, arrays, etc.) be destructured in a similar way, or can you only do this with tuples?

编辑:可以以类似的方式对任何事物(列表,数组等)进行解构,还是只能用元组执行此操作?

4 个解决方案

#1


Seeing your edit, I think what your asking about is Pattern matching.

看到你的编辑,我想你的问题是模式匹配。

And to answer your question: Yes, anything you can construct, you can also 'deconstruct' using the constructors. For example, you're probably familiar with this form of pattern matching:

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

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

However, there are more places where you can use pattern matching, other valid notations are:

但是,有更多地方可以使用模式匹配,其他有效表示法是:

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

Note that the last two examples are a bit different from the first to because they give different error messages when you call them with an empty list.

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


Although these examples are specific to lists, you can do the same with other data types, like so:

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

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

Again, the last function will also crash if you call it with Nothing.

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

To sum up; if you can create something using constructors (like (:) and [] for lists, or (,) for tuples, or Nothing and Just for Maybe), you can use those same constructors to do pattern matching in a variety of ways.

总结一下;如果你可以使用构造函数创建一些东西(比如(:)和[]代表列表,或(,)代表元组,或者Nothing和Just for Maybe),你可以使用相同的构造函数以各种方式进行模式匹配。

#2


Am I right about this behavior?

我对这种行为是对的吗?

Yes. The names exist only in the block where you have defined them, though. In your case, this means the logical unit that your where clause is applied to, i.e. the expression inside fList.

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

#3


Another way to look at it is that code like this

另一种看待它的方法就是像这样的代码

x where x = 3

is roughly equivalent to

大致相当于

let x = 3 in x

#4


Yes, you're right. Names bound in a where clause are visible to the full declaration preceding the where clause. In your case those names are f and bar.

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

(One of the hard things about learning Haskell is that it is not just permitted but common to use variables in the source code in locations that precede the locations where those variables are defined.)

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

The place to read more about where clauses is in the Haskell 98 Report or in one of the many fine tutorials to be found at haskell.org.

有关where子句的更多信息,请参阅Haskell 98报告或haskell.org上的许多精彩教程之一。

#1


Seeing your edit, I think what your asking about is Pattern matching.

看到你的编辑,我想你的问题是模式匹配。

And to answer your question: Yes, anything you can construct, you can also 'deconstruct' using the constructors. For example, you're probably familiar with this form of pattern matching:

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

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

However, there are more places where you can use pattern matching, other valid notations are:

但是,有更多地方可以使用模式匹配,其他有效表示法是:

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

Note that the last two examples are a bit different from the first to because they give different error messages when you call them with an empty list.

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


Although these examples are specific to lists, you can do the same with other data types, like so:

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

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

Again, the last function will also crash if you call it with Nothing.

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

To sum up; if you can create something using constructors (like (:) and [] for lists, or (,) for tuples, or Nothing and Just for Maybe), you can use those same constructors to do pattern matching in a variety of ways.

总结一下;如果你可以使用构造函数创建一些东西(比如(:)和[]代表列表,或(,)代表元组,或者Nothing和Just for Maybe),你可以使用相同的构造函数以各种方式进行模式匹配。

#2


Am I right about this behavior?

我对这种行为是对的吗?

Yes. The names exist only in the block where you have defined them, though. In your case, this means the logical unit that your where clause is applied to, i.e. the expression inside fList.

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

#3


Another way to look at it is that code like this

另一种看待它的方法就是像这样的代码

x where x = 3

is roughly equivalent to

大致相当于

let x = 3 in x

#4


Yes, you're right. Names bound in a where clause are visible to the full declaration preceding the where clause. In your case those names are f and bar.

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

(One of the hard things about learning Haskell is that it is not just permitted but common to use variables in the source code in locations that precede the locations where those variables are defined.)

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

The place to read more about where clauses is in the Haskell 98 Report or in one of the many fine tutorials to be found at haskell.org.

有关where子句的更多信息,请参阅Haskell 98报告或haskell.org上的许多精彩教程之一。