Haskell “的正式定义;“一元函数”;

Haskell “的正式定义;“一元函数”;,haskell,functional-programming,monads,Haskell,Functional Programming,Monads,维基上说: 一元函数(即使用单元值作为 它们的参数或返回值) 我的理解是一个函数接受或返回一个单子就是一元函数,但当我遇到这个问题时,它的定义似乎更严格 作者说: 一元函数是产生一元值的函数。(注 我们没有提到它的输入类型) 及 函数的形式为f::a->mb,其中a是 单子的内部值。(称这些为经典的一元函数) 表单f::anything->mb的函数,其中 功能真的不重要。(称这些为松散的一元函数) 看起来这个定义很严格,很正式,但我找不到任何地方可以说明 那么到底什么是一元函数呢?我知道你提到

维基上说:

一元函数(即使用单元值作为 它们的参数或返回值)

我的理解是一个函数接受或返回一个单子就是一元函数,但当我遇到这个问题时,它的定义似乎更严格

作者说:

一元函数是产生一元值的函数。(注 我们没有提到它的输入类型)

函数的形式为
f::a->mb
,其中
a
是 单子的内部值。(称这些为经典的一元函数)

表单
f::anything->mb
的函数,其中 功能真的不重要。(称这些为松散的一元函数)

看起来这个定义很严格,很正式,但我找不到任何地方可以说明


那么到底什么是一元函数呢?

我知道你提到了

在您的上下文中,“一元函数”指定要编写更大函数的函数,利用
(>>=)
返回所做的隐式上下文处理

示例:假设您有一个
Map
Map
s来表示4个组合的输出值 “aa”->1,“ab”->2,“bc”->3,“bd”->4

表示
lookup::ordk=>k->mapka->可能是a

这里
查找
是所谓的“一元函数”
,它必须组成(在这里与自身一起)才能给出
类型的函数:Char->Char->Map2->Maybe Int

composedLookup a b m = do     
        v  <- lookup a m
        v' <- lookup b v
        return v'
编辑: 而
ma->b
类型的函数在
m
是一个comonad的上下文中被称为comonadic。 我发现这很有启发性,因为它最终从类型和应用的角度解释了monad和comonad


希望这有助于

让我们研究一下在函数的输入或输出中使用monad的可能性

  • 其中一个输入参数中的Monad:
    f::ma->X
    。因为对于我们拥有的任何monad
    return::a->ma
    ,我们都可以用f组合它并得到

    f . return :: a -> X
    
  • 纯输出:
    f::X->b
    。通过将它与来自另一边的返回进行组合,我们得到

    return . f :: X -> m b
    
  • 所以我们总是可以把一个纯输出转换成一元输出,把一元输入转换成纯输出。任何具有纯或一元输入/输出的函数都可以转换为形式

        f :: a1 -> ... -> an -> m b
    
    然而,反过来是不可能的(一般来说)

    我要说的是,“经典”和“松散”一元函数没有广泛使用。

    一个简短且(我希望)简单的答案是,一元函数的返回数据签名/类型与其输入数据签名/类型相同

    想象一下加号运算符的功能:

    def plus(a,b):
        return a+b
    
    这不是一元的,因为它接受一个元组,但返回一个值

    但改写为:

    def monad_plus(a,b):
        if b is None:
            return (a, None)
        else:
            return (a+b, None)
    
    然后,该函数的结果可以输入到另一个函数调用中,而无需任何更改

    然后,您可以创建一系列函数,这些函数既接受
    (a,b)
    输入,又返回相同的
    (a,b)
    输出

    def monad_mult(a,b):
        if b is None:
            return (a, None)
        else:
            return (a*b, None)
    
    def monad_div(a,b):
        if b is None:
            return (a, None)
        else:
            return (a/b, None)
    
    我认为,实际上,您应该处理退化情况,其中
    a○ None
    不应该对
    a
    执行任何更改,这就是为什么我明确添加了那些
    if is None
    测试的原因,但我欢迎对此提供建议


    实际的最终结果应该是,您能够将这些调用的整个集合串在一起,并提交它们的执行以多种方式执行-串行、分布式等,成批或按顺序对数据集执行,并且始终保持信心返回相同的结果。

    文章顶部指出了在其他地方找不到这些术语的主要原因,其中指出:它包含了我个人和直觉的一元函数思维方式“一元函数”不是一个严格定义的术语。一元函数是严格定义的,一元函数不是。如果你的意思是
    a->mb
    ,你可以说Kleisli arrow或monadic function。您可以调用
    ma->mb->mc
    一元函数。这取决于上下文,恐怕没有确切的答案。如果我们只知道这与你有什么关系,也许我们可以帮助你更好。请注意,我们讨论的是定义。每个人都可以自由定义他认为合适的术语。平心而论,一旦确定了某个术语,坚持自己的不同定义是不明智的。但是,正如你所说,你没有发现这些术语被广泛使用,因此要么从你引用的博客中继承定义,要么提出自己的定义。这种“经典”一元函数和“松散”一元函数之间的区别并没有很好的定义。没有“单子的内在价值”这样的东西。我不会把这篇博文看得太重。我们都喜欢分享我们发现新概念的旅程,但这并不意味着我们对旅程的理解会对其他人有所帮助,或者包含定义良好的标准概念。我会称
    a->mb
    a Kleisli箭头和
    ma->b
    a Cokleisli箭头。前者通常与单子相连,而后者通常更与单子相连。这样我们可以避免模糊的术语,这可能会引起一些混乱。请注意Kleisli箭头如何适合
    >=
    (bind)Monad方法,以及Cokleisli箭头如何适合
    extend
    (aka
    我认为
    MA->b
    类型的函数只有在
    m
    是一个comonad时才能合理地称为comonadic。我的错了,谢谢你的更正。答案按照编辑。
    def monad_plus(a,b):
        if b is None:
            return (a, None)
        else:
            return (a+b, None)
    
    def monad_mult(a,b):
        if b is None:
            return (a, None)
        else:
            return (a*b, None)
    
    def monad_div(a,b):
        if b is None:
            return (a, None)
        else:
            return (a/b, None)