了解绑定功能

Understanding bind function

在这篇article中,作者用这个例子解释了monad(我猜是用了Haskell):

bind f' :: (Float,String) -> (Float,String)

which implies that

bind :: (Float -> (Float,String)) -> ((Float,String) -> (Float,String))

并继续要求实现函数绑定并提供解决方案:

bind f' (gx,gs) = let (fx,fs) = f' gx in (fx,gs++fs)

我在理解解决方案时遇到问题。这在 C 或 Swift 中会是什么样子?

我已经尽我所能实现了这个例子,但我仍然坚持实现绑定:

let f: Float -> Float = { value in return 2 * value }
let g: Float -> Float = { value in return 10 + value }

let ff: Float -> (Float, String) = { value in return (f(value), "f called") }
let gg: Float -> (Float, String) = { value in return (g(value), "f called") }

在 C++ 中,我认为它看起来像这样:

#include <functional>
#include <string>
#include <utility>

using P = std::pair<float, std::string>;
using FP = std::function<P(P)>;

FP mbind(std::function<P(float)> f) {
    return [f](P in) {
        auto && res = f(in.first);
        return {res.first, in.second + res.second};
    };
}

在 C 中,您可以通过存储函数指针来执行类似的操作,但调用语法必须更加冗长,因为您需要显式传递状态。

在Swift中,可能是这样的:

let bind: (Float -> (Float, String)) -> ((Float, String) -> (Float, String)) = { 
    lhs in

    return { 
        rhs in

        let result = lhs(rhs.0)
        return (result.0, "\(result.1); \(rhs.1)" )
    }
}

这是 Writer monad 的 bind。该 monad 的 bind 函数应该做两件事:

  1. Float值执行计算。

  2. 更新现有日志(String 值)。

最初你有一个元组 (oldFloat,oldString) 并且想要将类型为 Float -> (Float,String) 的函数应用到这个元组。

您的函数从元组 (oldFloat,oldString) 和 returns 元组 (newFloat,newString) 中获取 oldFloat 值。

您希望 bind 函数有什么行为?我想你想要一个包含 newFloat 和更新日志 oldString ++ new string 的元组,对吧?这是它的直接实现:

bind f (oldFloat,oldString) =
    -- apply function f to oldFloat from tuple (oldFloat,oldString) 
    -- to get a new tuple (newFloat,newString)
    let (newFloat,newString) = f oldFloat
    -- you want from your bind function to get a tuple containing 
    -- a newFloat and a newString added to oldString
    in (newFloat, oldString ++ newString)