如何用任意一个函数来构成`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的论文 。