Объединение двух функций для применения их к одному и тому же вводу - PullRequest
4 голосов
/ 04 ноября 2019

Я новичок в Хаскеле и все еще думаю об этом. Я пытаюсь объединить две функции (isMark и isAlpha из Data.Char модуль в base пакет) в качестве первого аргумента для Data.Text.filter function,До сих пор я пробовал:

import qualified Data.Char as C
import qualified Data.Text as T
import           Data.Text (Text)

strippedInput :: Text -> Text
strippedInput input = T.filter (C.isMark || C.isAlpha) input

, который не работает, или

strippedInput input = T.filter (C.isMark . C.isAlpha) input

, но, очевидно, он тоже не работает, как тип C.isAlphaэто Char -> Bool, который затем становится входом для C.isMark, который также имеет тип Char -> Bool, поэтому типы не совпадают.

Я бы хотел получить "C.isMark ИЛИ C.isAlpha"логика в предикате, но из-за моих очень ограниченных знаний у меня закончились идеи о том, как искать решение.

Ответы [ 2 ]

6 голосов
/ 04 ноября 2019

Самое простое - использовать лямбда-выражение :

strippedInput :: Text -> Text
strippedInput input = T.filter (<b>\x -> C.isMark x || C.isAlpha x</b>) input

Кроме того, вы можете использовать тот факт, что функция является аппликативным функтором и, таким образом, работать с:

import Control.Applicative(liftA2)

strippedInput :: Text -> Text
strippedInput input = T.filter (<b>liftA2 (||) C.isMark C.isAlpha</b>) input
1 голос
/ 05 ноября 2019

Принятый ответ совершенно прав. Возможно, я бы хотел использовать аппликативный оператор;

strippedInput = T.filter $ (||) <$> C.isMark <*> C.isAlpha

Однако проблема с liftA2 заключается в том, что, как видно из названия, она связана только с двумя функциями параметров, и да, это нормально дляэтот вопрос. Тем не менее ... Haskell предоставляет более разумную общую абстракцию для этой работы. В основном это называется монада функций, которая в основном обобщается как монада Reader, добавляя некоторые вспомогательные функции и возможности преобразователя. Однако для простоты мы можем попробовать здесь монаду функции.

Монада Function / Reader используется для объединения не только двух, но и неопределенного числа функций (каждая принимает два параметра), и в этом случае первый параметр подаетсяпредыдущий результат функции, а второй - общее состояние только для чтения (в данном случае это input)

Таким образом, ответ на этот вопрос также может быть следующим:

strippedInput = T.filter (C.isMark >>= (\b c -> b || C.isAlpha c) >>= return)

Однако, посколькупакет Data.Char полон проверок типа isThis, isThat, мы можем показать, как можно расширить этот подход.

strippedInput = T.filter (C.isMark >>= (\b c -> b || C.isAlpha  c)
                                   >>= (\b c -> b || C.isSymbol c)
                                    .
                                    .
                                   >>= return)

и ... никто не мешает вам сделать функцию сравнения, такую ​​как

orWith f      = \b c -> b || f c
strippedInput = T.filter $ C.isMark >>= orWith C.isAlpha
                                    >>= orWith C.isSymbol
                                     .
                                     .
                                    >>= return
...