Function 如何用任意算术的函数组合'not'?
当我有某种类型的函数时,比如Function 如何用任意算术的函数组合'not'?,function,haskell,functional-programming,composition,Function,Haskell,Functional Programming,Composition,当我有某种类型的函数时,比如 f :: (Ord a) => a -> a -> Bool f a b = a > b 我想做一个函数,它用not来包装这个函数 e、 g.使函数像这样 g :: (Ord a) => a -> a -> Bool g a b = not $ f a b 我可以让combinator像 n f = (\a -> \b -> not $ f a b) 但我不知道怎么做 *Main> let n f =
f :: (Ord a) => a -> a -> Bool
f a b = a > b
我想做一个函数,它用not来包装这个函数
e、 g.使函数像这样
g :: (Ord a) => a -> a -> Bool
g a b = not $ f a b
我可以让combinator像
n f = (\a -> \b -> not $ f a b)
但我不知道怎么做
*Main> let n f = (\a -> \b -> not $ f a b)
n :: (t -> t1 -> Bool) -> t -> t1 -> Bool
Main> :t n f
n f :: (Ord t) => t -> t -> Bool
*Main> let g = n f
g :: () -> () -> Bool
我做错了什么
还有一个额外的问题是,对于参数更多、最少的函数,我如何做到这一点
t -> Bool
t -> t1 -> Bool
t -> t1 -> t2 -> Bool
t -> t1 -> t2 -> t3 -> Bool
您的n组合符可以写为:
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和Ralf Hinze的论文。除非你想去破解类型类,这最好留给思考实验和概念证明,否则你就不能概括为多个论点。不要尝试 至于你的主要问题,这是用Conal Elliott的语义编辑器combinators最优雅地解决的。语义编辑器组合器是一个类型如下的函数:
(a -> b) -> F(a) -> F(b)
其中F(x)
是一个涉及x
的表达式。还有一些“逆变”编辑器组合器,它们采用a(b->a)
。直观地说,编辑器组合器选择某个较大值的一部分进行操作。您需要的结果称为result
:
result = (.)
查看您试图操作的表达式的类型:
a -> a -> Bool
这种类型的结果(codomain)是a->Bool
,而这种类型的结果是Bool
,这就是您试图应用而不是的内容。因此,要将not
应用于函数f
的结果,您需要编写:
(result.result) not f
这是一个很好的概括。这里还有几个组合器:
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]
如果你想将而不是应用到Bool,你只需说出到达那里的路径:
(result.left.result.second) not x
哦,如果你已经了解了函子,你会注意到,fmap
是一个编辑器组合器。事实上,上述内容可以拼写为:
(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 (<)
模块Pred,其中
类谓词a where
补语::a->a
实例谓词Bool where
补充=不
实例(谓词b)=>谓词(a->b),其中
补码f=\a->补码(f a)
--如果你想变得神秘,那么
--补语=(补语。)
--也有效
通用电气:作战需求文件a=>a->a->Bool
ge=complete(它在ghci中也起作用。让g:(Ord a)=>(a->a->Bool);g=n F在(谓词b)=>谓词(a->b)
)中有一个看似自由的a
是一个愉快而有用的想法。使用SEC符号,您还可以将函数的实例编写为complete=result-complete,这相当于Norman的“神秘”版本,写得不那么神秘/更规则。这是否依赖于函数的同构性?例如,我如何使用类型类定义“比较器”"1..n个元组的函数,它给出了第一个元组uncurry compare$Tm
的结果,其中结果不是EQ
?@Dominic:我想我不理解你的问题。但是它适用于任何返回Bool
的函数,不管参数的类型是什么。异构类型的参数很好。例如,给定成员::Eq a->a->a->[a]->Bool
,补码成员
正是您所期望的。对;我没有解释得那么好。假设我想对类型类执行“任意算术”但是typeclass中定义的函数不是a->a
,而是做了一些其他的事情。一个简单的例子是一个计算其参数的任意算术函数。我显然写不出来:class Count a where Count::a->Int Count=1 instance(Count b)=>Count(a->b)where Count=1+(Count(未定义::b))的预期效果是count 1=>1
和count 1'a'Nothing=>3
。GHC抱怨b
在最后一行中含糊不清。我喜欢这种对秒的解释。更多信息,请参阅。小更正:我称不是
编辑器和<代码>结果<代码> >代码>左,<代码>第二版/代码>等“编辑器组合器”,因为它们将编辑器转换成一个组合。考虑将.NET-tag添加到右面板上的有趣标签;或者作为result.result,result.result.result,等等,你可以穿插其他的SECs,比如first,second和fmap。我怀疑这仅仅是函数组合符号的中缀,使人们不认为它是一元的,因此可以以这种强大的方式进行组合。