lomeo: (лямбда)
[personal profile] lomeo
Наконец то! SPJ предлагает добавить views patterns в Haskell'.

Views patterns - это не совсем views, вернее, совсем не views :-) Это, скорее, другая форма записи pattern guards - более легкая и почти элегантная ;-) Здесь SPJ ещё в далёком 97-м рассматривал pattern guards как альтернативу views.

Мой интерес к views растёт с одной задачи, которую рассматривали мы с [livejournal.com profile] thesz. Ниже я описал pattern guards как раз на её примере.


Для тех, кто не в курсе насчет views и pattern guards я попытаюсь объяснить задачи, которые они решают. Вернее, какую пользу от них вижу я :-)

Механизм паттерн матчинга очень удобен при декларативном описании - его лаконичность и однозначность делают код более простым и понятным. Однако, он использует внутреннее представление типа и, следовательно, типы, потроха которых скрыты от их пользователя, несовместимы с механизмом паттерн матчинга. Зачем нужны такие типы, думаю, понятно. По сути, причина одна - это сокрытие реализации и предоставление интерфейса работы со значениями типа с целью задания ограничений на работу с типом. Модульность, инкапсуляция и всё такое.

Разумеется, очень хотелось бы, несмотря на заявленные ограничения, воспользоваться паттерн матчингом. Так вот, для того, чтобы значение типа можно было сравнить с неким образцом (паттерном), необходимо это значение представить в виде другого значения, которое мы уже можем сравнить. Это "другое" значение называется view.

В view pattern эта проблема решается так. Допустим, у нас есть тип очереди

data Queue a = ...


и функция для перевода очереди в список:

queueToList :: Queue a -> [a]


Предположим, мы хотим узнать, содержат ли первые пять значений единички. Для списка это паттерн 1:1:1:1:1:_. С помощью view patterns это запишется так:

fiveOnes :: Queue Integer -> Bool
fiveOnes (Just . queueToList -> 1:1:1:1:1:_) = True
fiveOnes _ = False


Зачем здесь Just? Дело в том, что view pattern записывается в виде (expr -< pattern), где expr - обычное выражение Haskell, а pattern - соответственно, образец, с которым сравниваем view. Правила сравнения просты:


  • Считаем (expr v). В нашем примере - считаем (Just . queueToList) query.

  • Если результат Nothing - то считаем попытку неудачной.

  • Если результат Just x - то сравниваем x с образцом pattern.



Вот и всё. Остальное в Trac'е.

Date: 2007-01-23 11:50 am (UTC)
From: [identity profile] thesz.livejournal.com
Нормалёк. Я думал, что сложнее получится.

Date: 2007-01-23 12:58 pm (UTC)
From: [identity profile] lomeo.livejournal.com
Да по большому счёту те же pattern guards. Они там ещё мастурбируют над синтаксисом.

Date: 2007-01-23 12:29 pm (UTC)
From: [identity profile] migmit.livejournal.com
М-м-м... Что-то не очень понял. Почему не просто
fiveOnes x = case queueToList x of 1:1:1:1:1:_ -> True
Да, при этом вводится лишняя переменная x, но, ИМХО, её и так придётся вводить во многих случаях (лямбдой).

Date: 2007-01-23 12:57 pm (UTC)
From: [identity profile] lomeo.livejournal.com
Всё верно, но это же не настоящий view. Видимо, неудачный пример. Допустим, что у нас asList :: Queue a -> Maybe [a]. Тогда в выражении

fiveOnes (asList -> 1:1:1:1:1_) идентификатор asList можно рассматривать как view.
...Ну, допустим, можно ;-)

Date: 2007-01-23 06:54 pm (UTC)
From: [identity profile] nealar.livejournal.com
Объяснение, что такое views - супер!
Идея реализовать такое в Haskell - здорово! Я давно хотел более абстрактные pattern guards. Но смирился с их несуществованием, как ранее смирился с негибким switch/case в С.
Зачем нужен Just - не вкурил.

Date: 2007-01-24 03:51 pm (UTC)
From: [identity profile] thesz.livejournal.com
Сравнение может провалиться. Не всегда же очереди содержат пять единиц в начале. ;)

Date: 2007-01-24 04:10 pm (UTC)
From: [identity profile] lomeo.livejournal.com
Полагаю, дело не в этом. Для проверки содержания единиц в начале достаточно пользоваться view без Maybe обертки.
Проблема возникает в случае, когда для значения типа нет конкретного представляения в другом типе.

Это IMHO, разумеется.

Да! Основное отличие pattern guards от view patterns это не то, что писать меньше, а то, что views могут быть вложенными, т.к. это не гарды, а паттерн (это я не сам догадался - с хаскель мейллиста прочел)

data Q a = Q [a]

toList (Q xs) = Just xs

toNum "1" = Just 1
toNum _   = Nothing

startsWithOne :: Q a -> Bool
startsWithOne (toList -> (toNum -> 1):_) = True
startsWithOne _                          = False

Date: 2007-01-24 04:18 pm (UTC)
From: [identity profile] thesz.livejournal.com
Ага, понятно. Я думал, x -> Maybe y нужен везде.

Date: 2007-01-24 04:25 pm (UTC)
From: [identity profile] lomeo.livejournal.com
Теперь мне непонятно. Ну да. Этот тип нужен во всех view.

Мою фразу "Для проверки содержания единиц в начале достаточно пользоваться view без Maybe обертки." стоит расценивать только как "было бы достаточно, если бы это позволялось" ;-)

Date: 2007-01-24 04:46 pm (UTC)
From: [identity profile] thesz.livejournal.com
Ага, понятно. ;)

Date: 2007-01-24 05:47 pm (UTC)
From: [identity profile] nealar.livejournal.com
То есть, это фича такая - везде, где есть view, должен быть maybe? Чисто by design?

Date: 2007-01-24 08:11 pm (UTC)
From: [identity profile] lomeo.livejournal.com
Ну, я так понял.

demand always

Date: 2008-08-27 10:49 pm (UTC)
From: (Anonymous)
obstruction start excise, notional. </ color>

Profile

lomeo: (Default)
Dmitry Antonyuk

September 2025

S M T W T F S
 123456
78910111213
14 151617181920
21222324252627
282930    

Style Credit

Expand Cut Tags

No cut tags
Page generated Feb. 27th, 2026 04:39 am
Powered by Dreamwidth Studios