haskell - 是否可以根据具体情况定义高阶 "opposite"函数?

标签 haskell

我是 Haskell 新手。我正在尝试在 Haskell 中创建一种迷你语言,并且希望如果可能的话有一个名为 opp (“opposite”的缩写)的高阶函数,它将许多熟悉的函数转换为它们明显的函数对立面。例如,opp succ 将是函数 predopp head 将是 last,依此类推。对于将函数转换为相反函数的含义,我没有一些一般性定义:我只想挑选几个关键示例并声明它们的相反函数。所以我想要一个几乎从未定义的高度多态函数。

困难似乎在于我想通过名称而不是其本质(可以这么说)来识别函数。这种困难的一个表现是,如果我写

opp succ = pred

然后 Haskell 将 succ 视为变量,因此给我一个常量函数,该函数始终采用值 pred。我真正想说的是,“如果您看到字符串 opp succ,那么可以将其视为 pred 的另一个名称。”但经过一段时间的搜索后,我不知道如何做到这一点(如果可能的话)。

总而言之,我想定义一个函数

opp::(a -> b) -> (a -> b)

通过说类似的话

opp succ = pred

opp pred = succ

opp head = 最后

opp 最后 = 头

只要我愿意,就可以添加到这个列表中。显然我不能那样做,但是有没有一些不可怕的方法可以达到相同的效果?

最佳答案

是的,你可以,但是你需要 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

使用示例:

> head' [1,2,3]
1
> opp head' [1,2,3]
3

工作原理

首先是Opposite类(class)。这只是描述了一个f a b可以由 (a -> b) 的两个函数构造而成(正常和相反的功能)。

接下来是数据类型 FunctionAndOpposite被定义为。这仅存储两个函数。现在标准函数和 this 都是类的实例 Opposite 。函数实例只是丢弃相反的函数。

现在是opp可以定义函数。这只是从 FunctionAndOpposite 中取出第二个函数。 .

最后我们得到了将所有内容组合在一起的行:

type a :<-> b = forall f. Opposite f => f a b

它定义的是一个类型同义词,它接受两个输入类型 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有关更多详细信息,但请注意,要理解这一点,您需要了解镜头概念,这是一项相当大的工作。

关于haskell - 是否可以根据具体情况定义高阶 "opposite"函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24241367/

相关文章:

haskell - cofree comonad 的可展开实例

haskell - GHC评估策略

haskell - 使用 Maybe 和 Writer 过滤列表并跟踪过滤器命中

function - 这个函数或模式有名字吗?

haskell - 类型族和类型构造函数

algorithm - 检查数值约束表达式的允许值的等价性/子集

java - 在服务接口(interface)上,公开 doSomethingOnUser(user : User) or doSomethingOnUser(userId: String)

database - 就适合与 (SQLite) 数据库交互的函数的 Haskell 测试框架提供建议

haskell - 将 Haskell 的 GHCi 中的工作目录更改为带空格的路径

Haskell:此代码中错误 "Ambiguous type variable ... ` Integral t' ... `RealFrac t' ..."的来源是什么?