Рассмотрим следующие типы данных и синонимы шаблонов:
{-# LANGUAGE PatternSynonyms, NamedFieldPuns #-}
data Foo = Foo {
a :: Int
, b :: String
, c :: Maybe Bool
}
pattern Bar a b <- Foo { a, b }
pattern Baz c <- Foo { c }
Я хотел бы сопоставить a Foo
, но получить все a
, b
и c
. Что-то вроде этого (недопустимый Haskell):
showit :: Foo -> String
showit (Bar a b & Baz c) = show a ++ b ++ show c
Один из вариантов - использовать ViewPattern
:
dup :: a -> (a, a)
dup a = (a, a)
showall' :: Foo -> String
showall' (dup -> (Bar a b, Baz c)) = show a ++ b ++ show c
Но это приводит к не исчерпывающему предупреждению о матче. Но мы знаем, что Bar
и Baz
неопровержимы, так что совпадение каждого также неопровержимо.
Как это можно выразить без предупреждения компилятора?
Мотивация заключается в том, чтобы иметь мелкозернистые синонимы паттернов с полями большого типа данных и разрешать вызывающим абонентам извлекать только нужные поля, похожие на записи с NamedFieldPuns
. Синонимы синтаксиса еще не поддерживают синтаксис записи, но он работает: https://ghc.haskell.org/trac/ghc/ticket/8582
В моем случае я не могу выставить конструктор из модуля, так как я использую шаблон "умный конструктор" и, следовательно, не могу дать вызывающим абонентам преимущество сопоставления записей с NamedFieldPuns
.
Смотрите qaru.site/info/207463/... как вдохновение. Я пытаюсь расширить идею в этом ответе, чтобы позволить вызывающим абонентам произвольно извлекать n из m полей, для довольно большого m.
Edit: Оказывается, существует довольно широкая проблема с PatternSynonyms
и проверкой исчерпывающей информации: https://ghc.haskell.org/trac/ghc/ticket/10339
Это, похоже, делает синонимы синтаксиса, используемые в качестве экстракторов полей, очень неприятны при компиляции с включенными предупреждениями.