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


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.