我是Haskell的新手.我试图在Haskell中创建一个迷你语言,并希望尽可能使用一个高阶函数opp(简称为"对立")将一些熟悉的函数转换为明显的对立面.例如,opp succ将是函数pred,opp head将是last,等等.我没有一些关于将函数转换为相反函数的含义的一般定义:我只想选择几个关键示例并声明它们的对立面.所以我想要一个几乎没有定义的高度多态函数.
困难似乎是我想通过他们的名字而不是他们的本质来识别这些功能(可以这么说).这种困难的一个表现就是如果我写的话
opp succ = pred
然后Haskell视为succ一个变量,因此给了我一个始终取值的常数函数pred.我真正想要的是说更多的话,"如果你看到这个字符串,opp succ那么就把它想象成另一个名字pred." 但经过一段时间的搜索,我无法找到如何做到这一点(如果可能的话).
总而言之,我想定义一个函数
opp :: (a -> b) -> (a -> b)
通过说出类似的话
opp succ = pred
opp pred = succ
opp head = last
opp last = head
并在我想要的时候添加到此列表中.显然我不能这样做,但有一些非可怕的方法来达到同样的效果吗?
Dav*_*ani 11
是的,你可以,但是你需要RankNTypes才能有一个很好的实现.
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE RankNTypes #-}
module Opposites where
class Opposite f where
makeOpposite :: (a -> b) -> (a -> b) -> f a b
data FunctionAndOpposite a b = FunctionAndOpposite (a -> b) (a -> b)
instance Opposite (->) where
makeOpposite = const
instance Opposite FunctionAndOpposite where
makeOpposite = FunctionAndOpposite
opp :: FunctionAndOpposite a b -> a -> b
opp (FunctionAndOpposite _ f) = f
type a :<-> b = forall f. Opposite f => f a b
succ' :: Enum a => a :<-> a
succ' = makeOpposite succ pred
pred' :: Enum a => a :<-> a
pred' = makeOpposite pred succ
head' :: [a] :<-> a
head' = makeOpposite head last
last' :: [a] :<-> a
last' = makeOpposite last head
Run Code Online (Sandbox Code Playgroud)
用法示例:
> head' [1,2,3]
1
> opp head' [1,2,3]
3
Run Code Online (Sandbox Code Playgroud)
这个怎么运作
首先,有Opposite班级.这只是描述了一个f a b可以用(a -> b)(正常函数和相反函数)两个函数构造的函数.
接下来,FunctionAndOpposite定义数据类型.这只是存储这两个功能.现在这两个标准函数,都是这个类的实例Opposite.函数实例只丢弃相反的函数.
现在opp可以定义该功能.这只需要第二个功能FunctionAndOpposite.
最后,我们得到了将它们汇集在一起的线:
type a :<-> b = forall f. Opposite f => f a b
Run Code Online (Sandbox Code Playgroud)
它定义的是一个类型同义词,它接受两种输入类型a和b,然后返回一个类型f a b,其中f可以是任何类型Opposite(取决于所需的).
(这:<->只是启用类型的奇特名称TypeOperators).
考虑一下代码head' [1,2,3].head'有类型forall f. Opposite f => f [a] a.但是,由于它被用作函数应用程序(因为它后面有一个参数),f必须是->.因此,使用函数实现Opposite,返回第一个参数makeOpposite,即head(很棒!).
但是,让我们说opp head' [1,2,3].opp有类型FunctionAndOpposite a b -> a -> b,所以f必须FunctionAndOpposite.因此,调用FunctionAndOpposite实例,Opposite使用两个参数创建数据类型makeOpposite.opp然后拔出第二个函数,即last.
顺便说一句,这是使用lens库中使用的类似技术完成的Isomorphism.同构基本上是一对彼此相反的函数.如(+2)和(-2),reverse和它本身.这通常可能是一个更有用的概念,因为它允许您通过转换对数据类型运行操作.有关详细信息,请参阅Control.Lens.Iso,但请注意,要了解这一点,您需要了解镜头概念,这是一项非常重要的工作.
可以使用某种基于堆上闭包地址的哈希映射来识别函数。然后你就可以创建这样一个逆表。不幸的是,您不会真正得到您想要的东西,因为函数只是值,因此每当编译器(或运行时)决定这样做时就会创建它们。
\n\n例如,即使你这么说
\n\nopp head = last\nRun Code Online (Sandbox Code Playgroud)\n\n您可能(取决于编译器实现)一无所获
\n\nopp (\xce\xbbx.head x) \nRun Code Online (Sandbox Code Playgroud)\n\n事实上,您在函数值上没有可靠的身份 - 因此我认为没有可用的方法来完成您想做的事情。
\n| 归档时间: |
|
| 查看次数: |
328 次 |
| 最近记录: |