Functional programming 理解替换/`ap`类型签名和不同实现(函数式编程)时的混淆

Functional programming 理解替换/`ap`类型签名和不同实现(函数式编程)时的混淆,functional-programming,ramda.js,category-theory,fantasyland,sanctuary,Functional Programming,Ramda.js,Category Theory,Fantasyland,Sanctuary,我是函数式编程的学生,如果我的问题听起来很奇怪的话,我很抱歉——我正试着围绕函数的给定类型签名以及它们是如何实现的来思考 查看ap(替换)的签名 (a)→ B→ (c)→ (一)→ (b)→ A.→ c 这里给出的是 consts=f=>g=>x=>f(x)(g(x)) 我想我能理解f是一个函数,它接受两个参数,a和b,并返回cg是一个函数,它接受a并返回b。因此g(a)返回b,因此f(a)(b)可以写成f(a)(g(a)),它返回c g(a)是b的替代品吗 好的,现在我正在研究另一个仍然有意

我是函数式编程的学生,如果我的问题听起来很奇怪的话,我很抱歉——我正试着围绕函数的给定类型签名以及它们是如何实现的来思考

查看
ap
(替换)的签名

(a)→ B→ (c)→ (一)→ (b)→ A.→ c

这里给出的是

consts=f=>g=>x=>f(x)(g(x))

我想我能理解
f
是一个函数,它接受两个参数,
a
b
,并返回
c
g
是一个函数,它接受
a
并返回
b
。因此
g(a)
返回
b
,因此
f(a)(b)
可以写成
f(a)(g(a))
,它返回
c

g(a)
b
的替代品吗

好的,现在我正在研究另一个仍然有意义的实现:

ap(Identity(Math.sqrt)、Identity(64))

类型签名

  • (f(a->b),f a)->f b
  • (a)→ B→ (c)→ (一)→ (b)→ A.→ c
  • 使用a=f、b=a和c=b重新写入第二个

  • (f->a->b)->(f->a)->f->b
  • 假定
    ap
    采用两个参数,其中,在第一个
    f
    中可以是包含函数
    a->b
    的某个函子,在第二个
    f
    中,可以是包含
    a
    的某个函子,返回一个函子,该函子将第一个函子的函数替换为端点
    b
    ,该函子包含
    a

    好吧,退一步,这两件事看起来大不相同,我无法想象他们是如何说同样的话的

  • const S=f=>g=>x=>f(x)(g(x))

  • ap(Identity(Math.sqrt)、Identity(64))

  • 根据我的理解,
    ap(F(g),F(a))
    可以表示为
    F(a).map(g)
    ,同样,我仍然很难将其等同于
    const S=F=>g=>x=>F(x)(g(x))
    。也许我误解了什么

    …也许我的误解与
    ap
    的表达有关,以及它与
    f=>g=>x=>f(x)(g(x))
    的关系,因为我可以看到它们是如何表达相同的签名的,但我看不到它们是一样的


    任何能在这里提供一些认知帮助的人,我都会非常感激它

    ap
    是一个转换的名称,它在大量称为应用程序函子的容器类型上表现出相同的行为。函数就是这样一种容器类型:它可以被视为返回值的容器

    你在我的要点中找到的
    S
    组合符来自非类型的Lambda演算,是一个函数的变换。它恰好也是函数的Applicative Functor的一个有效实现,同时也是Ramda和saccession的首选实现。这就是为什么您可以将
    ap
    用作
    S

    为了了解
    ap
    是如何成为
    S
    ,让我们看看
    ap
    的签名:

    Apply f=>(f(a->b),f a)->f b

    让我们通过咖喱化函数来去掉逗号。这将使接下来的步骤更容易执行:

    Apply f=>f(a->b)->f a->f b

    Apply f
    部分显示,无论我们在哪里看到
    fa
    ,我们都可以使用包含
    a
    的Applicative Functor容器。让我们通过将
    f
    替换为
    (函数x)
    来专门为函数容器指定此签名
    x
    是该函数的输入,接下来是输出

    (功能x)(a->b)->(功能x)a->(功能x)b

    这是这样的:给定从
    x
    a
    b
    的函数,以及从
    x
    a
    的函数,将函数从
    x
    返回到
    b

    由于构造函数关联性的工作方式,我们可以删除
    函数x
    周围的括号:

    函数x(a->b)->函数x a->函数x b

    编写
    函数ab
    的另一种方法是使用箭头符号:
    (a->b)
    ,因此在下一步中,我们只需这样做:

    (x->(a->b))->(x->a)->(x->b)

    最后,我们可以再次去掉额外的括号,并发现它是我们的组合符:

    (x -> a -> b) -> (x -> a) -> x -> b
    (a -> b -> c) -> (a -> b) -> a -> c
    

    首先,我认为对于非类型lambda演算中函数类型的应用函子为什么被称为替换,没有简单的解释。AFAIK,Schönfinkel最初称这种组合融合或融合函数

    为了专门化一般的应用函子类型
    (f(a->b),f a)->f b
    (无载波形式),我们需要知道参数化类型变量
    f
    在函数类型的上下文中准确表示什么

    正如每个函子一样,应用函子是在单个类型上参数化的。然而,函数类型构造函数需要两种类型——一种用于参数,另一种用于返回值。为了使函数成为(应用程序)函子的实例,我们必须忽略返回值的类型。因此,
    f
    表示
    (a->)
    ,即函数类型本身及其参数的类型。部分应用的函数类型构造函数的正确表示法实际上是前缀
    (>)a
    ,所以让我们坚持这一点

    接下来,我将用curry格式重写通用应用程序类型,并用
    (>)r
    替换
    f
    。我用另一个字母给d
    (f (a -> b), f a) -> f b
    f (a -> b) -> f a -> f b // curried form
    
    // substitution
    (->) r (a -> b) -> (->) r a -> (->) r b // prefix notation
    (r -> a -> b) -> (r -> a) -> (r -> b) // infix notation
    
    // omit unnecessary parenthesis
    (r -> a -> b) -> (r -> a) -> r -> b