Сочетание шаблонов

Рассмотрим следующие типы данных и синонимы шаблонов:

{-# 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 Это, похоже, делает синонимы синтаксиса, используемые в качестве экстракторов полей, очень неприятны при компиляции с включенными предупреждениями.

Ответ 1

Не уверен, что это вообще полезно, но я дам ему шанс. Было бы приемлемо любое из этих решений?

showit :: Foo -> String
showit [email protected](Bar a b) = show a ++ b ++ show (c x)

showit' :: Foo -> String
showit' [email protected](Bar a b) = show a ++ b ++ showthat x
  where
    showthat (Baz c) = show c