0

当我读到提升的概念时,它是这样实现的(在 Javascript 中)

const liftA2 = f => (a, b) => b.ap(a.map(f));

我意识到有一种情况liftA2会产生错误:when bis a Right/ Justand ais a Left/ ,因为当我们需要它成为部分应用的函数时Nothing,映射Left/不会对值做任何事情。Nothing

Whenabare both aLeft它不会爆炸,但当然返回Left的值将是我认为可能是一个问题的值,b具体取决于您的期望。

提升与这些类型一起使用的功能是否是一回事?在使用这样的功能之前,我是否应该系统地明确地防范这些情况?上述实现是否正确/完整?


您将在下面找到有关该问题的更多详细信息

让我们定义函数来提升
const add = a => b => a + b;

在基本Wrapper实现of的情况下apmap我们可以跟踪正在发生的事情

class Wrapper {
    constructor(value) {
        this.value = value;
    }
    static of(value) { return new Wrapper(value); }
    map(f) { return Wrapper.of(f(this.value)); }
    ap(a) { return this.map(a.value); }
}

const a = Wrapper.of(1);
const b = Wrapper.of(2);

// liftA2
const tmp = a.map(add); // Wrapper { λ }
b.ap(tmp); // Wrapper { 3 }

但是Eitheror的事情Maybe是他们有一个Left/ Nothingcasemap并且打算不做任何特别的ap事情

class Left {
    constructor(value) {
        this.value = value;
    }
    static of(value) { return new Left(value); }
    map(f) { return this; }
    ap(a) { return this; }
}

class Right{
    constructor(value) {
        this.value = value;
    }
    static of(value) { return new Right(value); }
    map(f) { return Right.of(f(this.value)); }
    ap(a) { return this.map(a.value); }
}

const a = Left.of(1);
const b = Right.of(2);

// liftA2 
const tmp = a.map(add); // Left { 1 }
b.ap(tmp); // Error because tmp's value is not a function
4

1 回答 1

1

我的 Javascript 有点基础(我用得不多)。但我认为,正如评论中所指出的那样,您的实施ap并没有按照您的意愿行事。

首先,看看这个关于起重是什么的类似问题的答案。它应该采用n参数函数并将其放入给定 Functor/Monad 的上下文中,其中每个参数都包含在该 Functor/Monad 中。

换句话说,如果f: 'a -> 'b -> 'c(一个接受两个类型参数并返回类型结果的函数'a'b那么'c我们可以使用lift2where:

lift2:: ('a -> 'b -> 'c) -> (M['a] -> M['b] -> M['c])

这将f变成一个接受 anM[a]和 anM[b]并返回 an的函数M[c]M在这种情况下是你的Eitheror Maybe)。

由于我更熟悉 F#,因此我将在此处使用它作为示例。如果我要在 F# 中实现lift2for Option(相当于Maybe),我会这样做:

let lift2 (f: 'a -> 'b -> 'c) : ('a option -> 'b option -> 'c option) =
  let f2 ao bo =
    match ao, bo with
    | Some a, Some b -> Some(f a b)
    | _, _ -> None
  f2

您在这里看到我匹配两种输入类型。两者都必须是 aSome才能返回一个Some值。否则我只返回一个None. 在 a Result(相当于 a Either)的情况下,我将不得不确定偏向匹配的方式。Left/Error就返回哪个值而言,它可以采取任何一种方式。

在 FSI 中使用上面的代码,我得到以下信息:

> let f' = lift2 f;;
val f' : (int option -> int option -> int option)

> f' (Some(2)) (Some(3));;
val it : int option = Some 5

> f' (Some(2)) None;;
val it : int option = None

> f' None (Some(3));;
val it : int option = None
于 2020-07-27T00:57:34.313 回答