函数自动打开/重写haskell中的值

  • 本文关键字:haskell 重写 函数 haskell
  • 更新时间 :
  • 英文 :


我做了一个函数,如下所示:

pen :: (a -> b) -> (b -> a) -> (b -> b) -> a -> a
pen conv rev app = rev . app . conv

其用途如下:

pen read show (x -> x + 1) "5"
"6"

我是Haskell的新手,我想知道Haskell标准库中是否存在这样的函数,以及它的名称,因为我在Hoogle上找不到它。

我还假设有一些方法可以在没有(a->b(->(b->a(->。。。只有一个双射函数,但我也不知道该怎么做。

干杯!

我认为这个函数的通用版本最标准的名称是dimap。不幸的是,它没有出现在Hoogle搜索中,因为Hoogle缺乏对涉及(->)的实例的支持。

无论如何,dimap是一个类型类方法(用于Profunctor类(,因此它比您想要的更通用(同样,fmap也比查找map的人实际想要的更一般(。专门用于函数的Profunctor实例,它仍然比您想要的更通用,因为它允许将其输入和输出参数任意转换为任何类型,因此它专门用于函数中的类型签名是:

dimap :: (a -> b) -> (c -> d) -> (b -> c) -> (a -> d)

它显然可以进一步专门化为您想要的函数pen

dimap :: (a -> b) -> (b -> a) -> (b -> b) -> (a -> a)

它不在base中,但包含在lens包或独立的profunctors包中:

> import Data.Profunctor   -- from "profunctors"
> dimap read show (x -> x + 1) "5"
"6"

类型为a -> b的Haskell函数显然不能是"双射"的,但如果使用lens包,则Iso表示双射函数。

您可以从函数及其逆函数中定义Iso,方法是:

> import Control.Lens
> showRead = iso show read

要使用此Iso作为包装器/展开器应用函数,可以使用Lens函数under:

> under showRead (+1) "5"
"6"

我想值得注意的是,showRead可能不是一个好的Iso(即不完全守法(,因为showread不是完美的逆。(也就是说,一些show实例产生的值不能是read返回以再现该值。(

Haskell的好处之一是,可以很容易地查找不知道名称的函数,只需根据它们的类型即可。把(a -> b) -> (b -> a) -> (b -> b) -> a -> a放在Hoogle中试试。在这种情况下,你会得到4个点击,但它们都在第三方库中。其中两个与您的函数完全相同,两个几乎相同,但更严格。

此外,请注意,您的函数的类型签名没有它可能的那么通用,并且所有结果都有一个更通用的类型签名:(a -> b) -> (c -> d) -> (b -> c) -> a -> d。使用不太通用的类型签名有点危险,因为它会导致编译器发现错误。例如,pen conv rev app = rev . conv是错误的,因为它跳过了app。使用您的类型签名,这会编译得很好,但会有运行时错误。对于更通用的类型签名,它将是在编译时捕获的类型错误。

最新更新