Чи є зручний спосіб використання шаблону як функції предиката?


10

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

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

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

Чи є більш складний / чистий спосіб зробити подібні речі? Або я йду про речі зовсім не так?


1
Можливо, це "особистий смак", але, якщо вам потрібен лише цей присудок в одному місці, я був би дуже задоволений тим letпунктом, який вам не подобається, - хоча я вважаю за краще рівнозначне whereзастереження, тому це не загрожує основним визначенням. Звичайно, якщо вам потрібна ця утиліта не раз, ви визначите її як функцію верхнього рівня.
— Робін Зігмонд

Це, безумовно, прекрасно працює. Моє запитання було дещо мотивоване тим, наскільки вражаюче типовим є Haskell. Зазвичай відчувається, що ідіоматичний Хаскелл має дуже мало дублювання ідей, і зводить пух до мінімуму. Тож навіть не обов'язково я вважаю, що let myPred...стиль поганий , але він відчуває себе набагато більш багатослівним, ніж я б очікував за дуже просту ідею, яка змушує мене замислитися, чи я гавкаю неправильне дерево.
— Девід Сампсон

2
Можливо, ви подивитеся на призми (з об'єктива). Вони схожі на першокласні композиційні візерунки
— luqui

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, щоб реалізувати це, не перевіривши кілька годин. Я спробую це і відредагую свою відповідь, чи зможу це зрозуміти, чи це глухий кут.

EDIT: Так, ви можете це зробити! Ось посилання на мій код, який реалізує все з нуля:

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.