我做了一个函数如下:
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 lacks support for instances involving (->)
.
无论如何,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
作为包装器/解包器应用函数,您可以使用镜头函数under
:
> under showRead (+1) "5"
"6"
我想值得注意的是,showRead
可能不是一个很好的 Iso
(即不完全合规),因为 show
和 read
不是完美的逆。 (也就是说,一些 show
实例产生的值不能被 read
返回以重现该值。)
关于haskell - 在haskell中自动解包/重新包装值的功能?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61234320/