Я написал несколько полезных функций для выполнения логических операций. Похоже на (a and b or c) `belongs` x
.
Благодаря Num
, IsList
и OverloadedLists
я могу использовать его для целых чисел и списков.
λ> (1 && 2 || 3) `belongs` [2]
False
λ> (1 && 2 || 3) `belongs` [1, 2]
True
λ> (1 && 2 || 3) `belongs` [3]
True
λ> :set -XOverloadedLists
λ> ([1, 2] && [2, 3] || [3, 4]) `contains` 1
False
λ> ([1, 2] && [2, 3] || [3, 4]) `contains` 2
True
Я так делаю:
newtype BoolLike a = BoolLike ((a -> Bool) -> Bool)
(&&) :: BoolLike a -> BoolLike a -> BoolLike a
BoolLike f && BoolLike g = BoolLike $ \k -> f k P.&& g k
infixr 3 &&
toBoolLike :: a -> BoolLike a
toBoolLike x = BoolLike $ \k -> k x
belongs :: Eq a => BoolLike a -> [a] -> Bool
belongs (BoolLike f) xs = f (\x -> x `elem` xs)
contains :: Eq a => BoolLike [a] -> a -> Bool
contains (BoolLike f) x = f (\xs -> x `elem` xs)
instance Num a => Num (BoolLike a) where
fromInteger = toBoolLike . fromInteger
Я собираюсь сделать его подходящим для любых типов, не конвертируя вручную a
в BoolLike a
.
Как я могу этого добиться?
Первая попытка:
class IsBool a where
type BoolItem a
toBool :: a -> BoolItem a
instance IsBool (BoolLike a) where
type BoolItem (BoolLike a) = BoolLike a
toBool = id
instance IsBool a where
type BoolItem a = BoolLike a
toBool = toBoolLike
Не смогли:
Conflicting family instance declarations:
BoolItem (BoolLike a) -- Defined at BoolLike.hs:54:8
BoolItem a -- Defined at BoolLike.hs:58:8