如何用任意一个函数来构成`not`?

当我有类似的function

f :: (Ord a) => a -> a -> Bool fab = a > b 

我想用不包含这个函数的函数。

比如像这样做function

 g :: (Ord a) => a -> a -> Bool gab = not $ fab 

我可以使combinator像

 nf = (\a -> \b -> not $ fab) 

但我不知道如何。

 *Main> let nf = (\a -> \b -> not $ fab) n :: (t -> t1 -> Bool) -> t -> t1 -> Bool Main> :tnf nf :: (Ord t) => t -> t -> Bool *Main> let g = nf g :: () -> () -> Bool 

我究竟做错了什么?

和额外的问题,我怎么能做到这一点与更多和更less的参数,例如

 t -> Bool t -> t1 -> Bool t -> t1 -> t2 -> Bool t -> t1 -> t2 -> t3 -> Bool 

除非你想要使用types类来进行黑客攻击,那么最好还是留下思考实验和概念certificate,否则就不会推广到多个参数。 不要尝试。

至于你的主要问题,这是用Conal Elliott的语义编辑组合器最优雅地解决的。 语义编辑器组合器是一个types如下的函数:

 (a -> b) -> F(a) -> F(b) 

其中F(x)是涉及x的某个expression式。 也有“逆变”编辑组合,它采取(b -> a)来代替。 直观上,编辑器组合器select一些较大值的一部分来操作。 你需要的那个叫做result

 result = (.) 

看看你想要操作的expression式的types:

 a -> a -> Bool 

这个types的结果(codomain)是一个 – > Bool,这个types的结果是Bool,这就是你不想应用的。 因此,如果not适用函数f的结果的结果,则可以这样写:

 (result.result) not f 

这美妙地概括。 以下是几个组合器:

 argument = flip (.) -- contravariant first f (a,b) = (fa, b) second f (a,b) = (a, fb) left f (Left x) = Left (fx) left f (Right x) = Right x ... 

所以如果你有一个types的值x

 Int -> Either (String -> (Int, Bool)) [Int] 

而且你不想申请Bool,你只需要说明如何到达那里:

 (result.left.result.second) not x 

哦,如果你已经到了fmap ,你会注意到fmap是一个编辑器组合器。 其实上面可以拼写成:

 (fmap.left.fmap.fmap) not x 

但是我认为使用扩展名更清晰。

请享用。

实际上,通过types类来执行任意的结构变得非常简单:

 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 (fa) -- if you want to be mysterious, then -- complement = (complement .) -- also works ge :: Ord a => a -> a -> Bool ge = complement (<) 

感谢您指出这个很酷的问题。 我喜欢Haskell。

你的n combinator可以写成:

 n = ((not .) .) 

至于你的奖金问题,典型的方法是创build几个这样的:

 lift2 = (.).(.) lift3 = (.).(.).(.) lift4 = (.).(.).(.).(.) lift5 = (.).(.).(.).(.).(.) 

等等

回复: 我做错了什么?

我认为你的combinator是好的,但是当你把它绑定到顶层的时候,Haskell的一个恼人的“默认规则”就会发挥作用,绑定不是泛化的:

 Prelude> :ty (nf) (nf) :: (Ord t) => t -> t -> Bool Prelude> let g = nf Prelude> :ty g g :: () -> () -> Bool 

我认为你可能会受到“单态限制”的打击,因为它适用于types类。 在任何情况下,如果你走出顶级循环,并把东西放到一个单独的文件中,并带有明确的types签名,那么它一切正常:

 module X where nf = (\a -> \b -> not $ fab) fab = a > b g :: Ord a => a -> a -> Bool g = nf 

奖金问题 :要做到这一点越来越多的types参数,你可以尝试玩types系统的坏血病技巧。 两篇论文是关于QuickCheck和Ralf Hinze的论文“ generics的generics”的 Hughes和Claessen的论文 。