Если Вы не хотите пойти, бездельничая с typeclasses, который лучше оставлен для мысленных экспериментов и подтверждения концепции, Вы просто не делаете вывод к нескольким аргументам. Не пробовать.
Что касается Вашего основного вопроса, это наиболее изящно решено с Conal Elliott семантический редактор combinators . Семантический редактор combinator является функцией с типом как:
(a -> b) -> F(a) -> F(b)
, Где F(x)
некоторое выражение, включающее x
. Существует также "контравариантный" редактор combinators, которые берут (b -> a)
вместо этого. Интуитивно, редактор combinator выбирает часть некоторого большего значения для работы на. Тот, в котором Вы нуждаетесь, называют result
:
result = (.)
Взгляд на тип выражения Вы пытаетесь воздействовать на:
a -> a -> Bool
результат (область изменения) этого типа a -> Bool
, и результат [1 121], что тип Bool
, и это - то, к чему Вы пытаетесь подать заявку not
. Таким образом для применения not
к результату результата функции f
Вы пишете:
(result.result) not f
Это красиво делает вывод. Вот являются еще много combinators:
argument = flip (.) -- contravariant
first f (a,b) = (f a, b)
second f (a,b) = (a, f b)
left f (Left x) = Left (f x)
left f (Right x) = Right x
...
Поэтому, если у Вас есть значение x
из типа:
Int -> Either (String -> (Int, Bool)) [Int]
И Вы хотите подать заявку not
к Bool, Вы просто обстоятельно объясняете путь для получения там:
(result.left.result.second) not x
, О, и если Вы добрались до Функторов уже, Вы заметите, что fmap
редактор combinator. На самом деле вышеупомянутое может быть записано:
(fmap.left.fmap.fmap) not x
, Но я думаю, что это более ясно использовать расширенные имена.
Обладают.
На самом деле выполнение произвольной арности с классами типа оказывается невероятно легким:
module Pred where
class Predicate a where
complement :: a -> a
instance Predicate Bool where
complement = not
instance (Predicate b) => Predicate (a -> b) where
complement f = \a -> complement (f a)
-- if you want to be mysterious, then
-- complement = (complement .)
-- also works
ge :: Ord a => a -> a -> Bool
ge = complement (<)
спасибо за указание на эту прохладную проблему. Я люблю Haskell.
Ваш n combinator может быть записан:
n = ((not .) .)
Что касается Вашего вопроса о премии, типичный путь вокруг состоял бы в том, чтобы создать несколько из них:
lift2 = (.).(.)
lift3 = (.).(.).(.)
lift4 = (.).(.).(.).(.)
lift5 = (.).(.).(.).(.).(.)
и т.д.
Ре: , Что я делаю неправильно? :
я думаю, что Ваш combinator прекрасен, но когда Вы позволяете - связывают его на верхнем уровне, одно из раздражающих 'правил Haskell по умолчанию' начинает действовать, и привязка не обобщена:
Prelude> :ty (n f)
(n f) :: (Ord t) => t -> t -> Bool
Prelude> let g = n f
Prelude> :ty g
g :: () -> () -> Bool
я думаю, что можно становиться ударенными 'ограничением мономорфизма', поскольку оно применяется к классам типа. В любом случае, если Вы выходите из цикла верхнего уровня и помещаете вещи в отдельный файл с явной подписью типа, все это хорошо работает:
module X where
n f = (\a -> \b -> not $ f a b)
f a b = a > b
g :: Ord a => a -> a -> Bool
g = n f
вопрос о Премии : чтобы сделать это со все большим количеством параметров типа, можно попытаться играть приемы цинги с системой классов типа. Двумя бумагами для консалтинга является Hughes и Claessen статья о QuickCheck и статья Ralf Hinze Дженерики для Масс .