【问题标题】:Using lift with the Either or the Maybe monad将 Lift 与 Either 或 Maybe monad 一起使用
【发布时间】:2020-11-16 00:21:47
【问题描述】:

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

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

我意识到liftA2 会产生错误的情况:当bRight/JustaLeft/Nothing,因为映射一个@当我们需要它成为部分应用的函数时,987654332@/Nothing 不会对值做任何事情。

ab 都是Left 时,它不会爆炸,但当然返回的Left 的值将是b 的值,我想这可能是问题取决于您的期望。

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


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

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

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

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 }

EitherMaybe 的问题在于,他们有Left/Nothing 的情况,其中mapap打算 什么都不做 p>

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

【问题讨论】:

  • 您的示例代码的问题是Right.prototype.ap 已损坏。它需要将a参数区分为LeftRight,它不能只访问它的.value
  • @geoffrey 好吧,它不能返回预期输出类型的 Right,因为没有构造一个值,所以它 has to 返回 Left 值.在这种特殊情况下,它基本上由 monad 接口指定。
  • @geoffrey "连 Right 都应该知道 Left 类型吗?" - 它们不是独立的、不同的类型,它们根本不是类型。它们是同一类型的值构造函数:Either。是的,任何Either 方法都需要知道LeftRight。在这方面,您使用两个 classes 的实现有点奇怪。当然你可以用动态调度来模拟模式匹配,但是ap需要做两次。
  • @geoffrey Shameless plug:我更新了我课程中type theory 的章节。它仍然需要修正错字等,但它是可读的。如果您仍然感兴趣..

标签: functional-programming lifting


【解决方案1】:

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

首先,请查看this answer 以了解有关起重首先是什么的类似问题。它应该采用 n 参数的函数并将其放入给定 Functor/Monad 的上下文中,其中每个参数都包含在该 Functor/Monad 中。

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

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

这会将f 变成一个函数,该函数接受M[a]M[b] 并返回M[c](在这种情况下,M 是您的EitherMaybe)。

由于我对 F# 比较熟悉,所以我将在此处使用它作为示例。如果我要在 F# 中为 Option 实现 lift2(相当于 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

你在这里看到我匹配两种输入类型。两者都必须是 Some 才能返回 Some 值。否则我只返回一个None。对于Result(相当于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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-02-09
    • 1970-01-01
    • 1970-01-01
    • 2012-06-02
    • 2021-09-04
    • 2014-10-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多