При деструктурировании кортежей в Haskell, где можно использовать элементы? - PullRequest
6 голосов
/ 11 января 2009

Я читаю учебник, в котором используется следующий пример (который я немного обобщу):

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

Мой вопрос заключается в том, что, кажется, вы можете ссылаться на x и bar по имени вне кортежа, где они получены. Казалось бы, это действует как разрушение списков параметров на других языках, если я верна. (Другими словами, мне не нужно было делать следующее:)

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

Прав ли я в этом поведении? Я никогда не видел, чтобы это упоминалось в учебниках / книгах, которые я читал. Может кто-нибудь указать мне больше информации по этому вопросу?

Редактировать : Можно ли что-то (списки, массивы и т. Д.) Деструктурировать аналогичным образом, или вы можете делать это только с кортежами?

Ответы [ 4 ]

13 голосов
/ 11 января 2009

Видя ваши правки, я думаю, что вы спрашиваете: Соответствие шаблону .

И чтобы ответить на ваш вопрос: Да, все, что вы можете построить, вы также можете «деконструировать», используя конструкторы. Например, вы, вероятно, знакомы с этой формой сопоставления с образцом:

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.

Подвести итог; если вы можете создать что-то, используя конструкторы (например, (:) и [] для списков, (,) для кортежей или Nothing и Just для Maybe), вы можете использовать те же конструкторы для сопоставления с образцом Разнообразие способов.

2 голосов
/ 11 января 2009

Прав ли я в этом поведении?

Да. Имена существуют только в блоке, где вы их определили. В вашем случае это означает логическую единицу, к которой применяется ваше предложение where, то есть выражение внутри fList.

1 голос
/ 11 января 2009

Еще один способ взглянуть на это - вот такой код

x where x = 3

примерно эквивалентно

let x = 3 in x
0 голосов
/ 11 января 2009

Да, вы правы. Имена, связанные в предложении where, видны для полного объявления, предшествующего предложению where. В вашем случае эти имена f и bar.

(Одна из трудностей в изучении языка Haskell заключается в том, что использование переменных в исходном коде не только разрешено, но и распространено в местах, предшествующих тем местам, где эти переменные определены.)

Место, где можно узнать больше о том, где находятся предложения, в Отчете Haskell 98 или в одном из множества тонких руководств, которые можно найти по адресу haskell.org.

...