Есть ли удобный способ использовать шаблон в качестве функции предиката?


10

Недавно я сталкивался с ситуациями, когда мне нужно передать предикатную функцию в другую функцию, и довольно часто логика, которую я ищу, по существу "соответствует ли это значение этому шаблону?"

Похоже, что сопоставление с образцом предпочтительнее в объявлениях, doблоках и списках, но есть ряд функций, которые принимают предикат a -> Bool, где было бы очень удобно как-то передать шаблон. Так , например, takeWhile, until, find, spanи т.д.

До сих пор я делал \a -> case a of MyCons _ -> True; otherwise -> Falseили писал именованную функцию а-ля, let myPred (MyCons _) = True; myPred _ = False inно они оба кажутся ужасно уродливыми и не очень идиоматичными. «Очевидный» (и неправильный) путь был бы чем-то вроде этого, \(MyCons _) -> Trueно это, естественно, выдает ошибку за частичность, и даже тогда кажется, что должен быть более чистый путь.

Есть ли более лаконичный / чистый способ сделать это? Или я поступаю совершенно неправильно?


1
Может быть, это вещь «личного вкуса», но, если вам нужен только этот предикат в одном месте, я был бы весьма доволен letпредложением, которое вам не нравится - хотя я предпочитаю эквивалентное whereпредложение, чтобы оно не загромождало основное определение. Конечно, если вам понадобится эта утилита более одного раза, вы определите ее как функцию верхнего уровня.
— Робин Зигмонд

Это конечно хорошо работает. Мой вопрос был несколько мотивирован тем, насколько впечатляюще лаконичен Хаскелл. Обычно кажется, что идиоматичный Haskell очень мало дублирует идеи и сводит пух к минимуму. Так что даже не обязательно, что я думаю, что let myPred...стиль плохой , но он кажется гораздо более многословным, чем я ожидал от очень простой идеи, которая заставляет меня задуматься, не лаю ли я не на том дереве.
— Дэвид Сэмпсон

2
Вы могли бы взглянуть на призмы (с объектива). Они как первоклассные композитные узоры
— Луки

1
Я думаю, что нам нужно увидеть пример того, где вы используете этот тип функции более высокого порядка. Часть меня хочет сказать, что проблема в дизайне, который требует такого предиката.
— Чепнер

способ Haskell98 для этого состоит в том, чтобы определить функцию сопоставления регистра (деконструкции) для вашего типа данных, например, maybe :: b -> (a -> b) -> Maybe a -> bи bool :: a -> a -> Bool -> aзатем использовать ее с булевы производящими функциями в качестве аргумента (ов). например myCons z f (MyCons x) = f x ; myCons z f _ = z, затем позвоните myCons False (const True) aMyConsValue. это почти то, что вы написали, просто есть еще один уровень «косвенности» / «абстракции» через функциональные аргументы, встроенный в него.
— Уилл Несс

Ответы:


7

Вы можете использовать расширение языка LambdaCase \case MyCons _ -> True; _ -> False, хотя это не спасает столько символов.

Я полагаю, что вы могли бы написать ряд функций constructedWith :: (Generic a) => (b -> a) -> a -> Bool, constructedWith2 :: (Generic a) => (b -> c -> a) -> a -> Boolно я недостаточно компетентен в Generics, чтобы реализовать его без нескольких часов тестирования. Я попробую это и отредактирую свой ответ, если смогу разобраться или это тупик.

РЕДАКТИРОВАТЬ: Да, вы можете сделать это! Вот ссылка на мой код, который реализует все это с нуля:

https://repl.it/@lalaithion/ConstructedWith

Однако лучше использовать что-то вроде http://hackage.haskell.org/package/generic-deriving-1.13.1/docs/Generics-Deriving-ConNames.html для всего общего кода.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.