组合函数组合: (.).(.) 是如何工作的? [英] Composing function composition: How does (.).(.) work?

查看:33
本文介绍了组合函数组合: (.).(.) 是如何工作的?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

(.) 有两个函数,它们接受一个值并返回一个值:

(.) takes two functions that take one value and return a value:

(.) :: (b -> c) -> (a -> b) -> a -> c

由于 (.) 需要 两个 参数,我觉得 (.).(.) 应该是无效的,但它完全没问题:

Since (.) takes two arguments, I feel like (.).(.) should be invalid, but it's perfectly fine:

(.).(.) :: (b -> c) -> (a -> a1 -> b) -> a -> a1 -> c

这里发生了什么?我意识到这个问题措辞不好......由于柯里化,所有函数实际上只需要一个参数.也许更好的说法是类型不匹配.

What is going on here? I realize this question is badly worded...all functions really just take one argument thanks to currying. Maybe a better way to say it is that the types don't match up.

推荐答案

让我们先玩一下机械校样的打字机.之后我会描述一种直观的思考方式.

Let's first play typechecker for the mechanical proof. I'll describe an intuitive way of thinking about it afterward.

我想应用 (.)(.) 然后我将应用 (.) 到结果.第一个应用程序帮助我们定义变量的一些等价.

I want to apply (.) to (.) and then I'll apply (.) to the result. The first application helps us to define some equivalences of variables.

((.) :: (b -> c) -> (a -> b) -> a -> c) 
      ((.) :: (b' -> c') -> (a' -> b') -> a' -> c') 
      ((.) :: (b'' -> c'') -> (a'' -> b'') -> a'' -> c'')

let b = (b' -> c') 
    c = (a' -> b') -> a' -> c'

((.) (.) :: (a -> b) -> a -> c) 
      ((.) :: (b'' -> c'') -> (a'' -> b'') -> a'' -> c'')

然后我们开始第二个,但很快就卡住了......

Then we begin the second, but get stuck quickly...

let a = (b'' -> c'')

这是关键:我们要让 b = (a'' -> b'') ->一个'' ->c'',但是我们已经定义了b,所以我们必须尝试统一 ---尽可能匹配我们的两个定义.幸运的是,它们确实匹配

This is key: we want to let b = (a'' -> b'') -> a'' -> c'', but we already defined b, so instead we must try to unify --- to match up our two definitions as best we can. Fortunately, they do match

UNIFY b = (b' -> c') =:= (a'' -> b'') -> a'' -> c''
which implies 
      b' = a'' -> b''
      c' = a'' -> c''

有了这些定义/统一,我们就可以继续应用

and with those definitions/unifications we can continue the application

((.) (.) (.) :: (b'' -> c'') -> (a' -> b') -> (a' -> c'))

然后展开

((.) (.) (.) :: (b'' -> c'') -> (a' -> a'' -> b'') -> (a' -> a'' -> c''))

清理干净

substitute b'' -> b
           c'' -> c
           a'  -> a
           a'' -> a1

(.).(.) :: (b -> c) -> (a -> a1 -> b) -> (a -> a1 -> c)

老实说,这有点违反直觉.

which, to be honest, is a bit of a counterintuitive result.

这是直觉.先来看看fmap

fmap :: (a -> b) -> (f a -> f b)

它将一个函数提升"为一个Functor.我们可以反复应用

it "lifts" a function up into a Functor. We can apply it repeatedly

fmap.fmap.fmap :: (Functor f, Functor g, Functor h) 
               => (a -> b) -> (f (g (h a)) -> f (g (h b)))

允许我们将一个函数提升到越来越深的Functors层中.

allowing us to lift a function into deeper and deeper layers of Functors.

原来数据类型(r ->)是一个Functor.

instance Functor ((->) r) where
   fmap = (.)

这应该看起来很熟悉.这意味着 fmap.fmap 转换为 (.).(.).因此,(.).(.) 只是让我们转换 (r ->) Functor 的更深层次的参数类型代码>.(r ->) Functor其实就是Reader Monad,所以分层Readers 就像拥有多种独立的全局、不可变状态.

which should look pretty familiar. This means that fmap.fmap translates to (.).(.). Thus, (.).(.) is just letting us transform the parametric type of deeper and deeper layers of the (r ->) Functor. The (r ->) Functor is actually the Reader Monad, so layered Readers is like having multiple independent kinds of global, immutable state.

或者像有多个不受 fmaping 影响的输入参数.有点像在 (>1) arity 函数的结果"上组合一个新的延续函数.

Or like having multiple input arguments which aren't being affected by the fmaping. Sort of like composing a new continuation function on "just the result" of a (>1) arity function.

最后值得注意的是,如果您认为这些东西很有趣,它构成了推导镜头控制背后的核心直觉.镜头.

It's finally worth noting that if you think this stuff is interesting, it forms the core intuition behind deriving the Lenses in Control.Lens.

这篇关于组合函数组合: (.).(.) 是如何工作的?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆