gpt4 book ai didi

javascript - RxJS.Observable 是单子(monad)吗?

转载 作者:行者123 更新时间:2023-12-03 00:01:32 24 4
gpt4 key购买 nike

Observable 真的是单子(monad)吗?它是否遵守 Monad 法律 (https://wiki.haskell.org/Monad_laws)?在我看来不像。但也许我的理解是错误的,有人可以对这个问题有所了解。我目前的推理是(我使用 :: 来表示“是一种”):

1) 左身份:返回 a >>= f ≡ f a

var func = x => Rx.Observable.of(10)

var a = Rx.Observable.of(1).flatMap(func) :: Observable
var b = func(1) :: ScalarObservable

haskell :
func = (\_ -> putStrLn "B")

do { putStrLn "hello"; return "A" } >>= func :: IO ()

func "A" :: IO ()

所以左身份不适用于 Observable。 Observable 显然不是 ScalarObservable。在 Haskell 中,类型是相同的 - IO () .

2) 权限标识: m >>= 返回 ≡ m
var x = Rx.Observable.of(1);

x.flatMap(x => Observable.of(x)) :: Observable
x :: ScalarObservable

haskell :
Just 2 >>= return  :: Num b => Maybe b
Just 2 :: Num a => Maybe a

与左身份相同的情况。可观察的!== ScalarObservable。而在 Haskell 中,类型保持不变,它是一个 Maybe ,里面有一个 Num 。

3)关联性

(m >>= f) >>= g ≡ m >>= (\x -> f x >>= g)
var x = Rx.Observable.of(10)

var func1 = (x) => Rx.Observable.of(x + 1)
var func2 = (x) => Rx.Observable.of(x + 2)


x.flatMap(func1).flatMap(func2) :: Observable
x.flatMap(e => func1(e).flatMap(func2)) :: Observable

haskell :
add2 x = Just(x + 2)
add1 x = Just(x + 1)

Just 2 >>= add1 >>= add2 :: Num b => Maybe b
Just 2 >>= (\x -> add1(x) >>= add2) :: Num b => Maybe b

这是唯一适用于 Observable 的定律。
但我不知道,也许这不应该像我那样推理。你怎么认为?

最佳答案

tldr; 是的。

JavaScript 是一种动态语言,在运行时具有鸭子类型,因此是 Observable 的实例。 class 相当于 ScalarObservable 的一个实例. RxJS 本身是用 TypeScript 编写的,这些不规则性不会在类型中出现,它们 - 正如@Bergi 在评论中所写的 - 是一种优化。另一方面,您完全正确:在名义类型系统中,类型不匹配可能是一个真正的问题,甚至是编译时错误。

现在,回答问题本身 - 请查看 Purescript library绑定(bind)到 RxJS:

foreign import data Observable :: Type -> Type

instance monoidObservable :: Monoid (Observable a) where
mempty = _empty

instance functorObservable :: Functor Observable where
map = _map

instance applyObservable :: Apply Observable where
apply = combineLatest id

instance applicativeObservable :: Applicative Observable where
pure = just

instance bindObservable :: Bind Observable where
bind = mergeMap

instance monadObservable :: Monad Observable

-- | NOTE: The semigroup instance uses `merge` NOT `concat`.
instance semigroupObservable :: Semigroup (Observable a) where
append = merge

instance altObservable :: Alt Observable where
alt = merge

instance plusObservable :: Plus Observable where
empty = _empty

instance alternativeObservable :: Alternative Observable

instance monadZeroObservable :: MonadZero Observable

instance monadPlusObservable :: MonadPlus Observable

instance monadErrorObservable :: MonadError Error Observable where
catchError = catch

instance monadThrowObservable :: MonadThrow Error Observable where
throwError = throw

假设 Purescript 类型是正确的:除了是常规的 Monad , Observable符合 MonadPlusMonadError类。 MonadPlus允许组合计算,而 MonadError允许中断或跳过计算的某些部分(在 Observable 的情况下,我们也可以轻松地重试计算)。 Observable不仅是一个monad,而且是一个非常强大的monad——甚至可能是主程序中使用的最强大的monad 流$ .

我没有任何正式的证明,但可以简短地描述如何使用 Observable 来建模或替换 https://wiki.haskell.org/All_About_Monads 中描述的 monads。 .

也许 可能不会返回结果的计算

非结果可以表示为常规 JS undefinedEMPTY溪流。

错误 可能失败或抛出异常的计算

您可以抛出常规 JS 错误或返回更多惯用语 throwError从一元绑定(bind)。错误可以被捕获,然后被处理或用于重试计算。抛出错误会立即停止正在进行的计算。

列表可以返回多个可能结果的非确定性计算

List 有点像 Observable 的弟弟,完全没有时间维度。任何可以通过列表操作表达的东西都可以精确地映射到可观察对象上的操作。您可以通过 Observable.from 轻松提升列表并使用 .toList() 降级到 observable .作为原生,列表的性能将比可观察的好得多。但请记住,列表是急切的,可观察是惰性的,因此在某些情况下,可观察可能会胜过列表。

IO 执行 I/O 的计算

任何 IO 操作(网络、磁盘等)都可以轻松包装/提升到可观察世界。

国家保持状态的计算

行为主体

读者从共享环境中读取的计算

从消费者的 Angular 来看,Observable 的实例来自哪里根本无关紧要。例如:如果您将配置声明为 observable,您可以轻松更改提供值的确切环境。

作家 除了计算值外还写入数据的计算

最简单的选择是返回两个流,一个带有值,另一个带有日志/辅助数据。

可以中断和重新启动的计算

要中断计算,您可以抛出错误,请使用运算符,例如 .switchMap , .takeUntil , 明确取消订阅或 .mergeMapEMPTY .访问某种形式的缓存以从任意步骤重新启动确定性计算是非常简单的:只需将您的计算拆分为较小的 observables 并在计算后缓存它们的结果;仅当缓存为空时重新启动运行计算 - 否则使用缓存值。

如果你决定使用 observable 来表示你的计算结构——你不仅可以建模/替换实践中最常见的 monad,而且你的计算在风格上会自动响应。此外,如果您坚持只使用可观察的,您的计算将是同质的,这意味着几乎不需要或根本不需要 monad 转换器和由它们引入的意外复杂性。
我的工作假设是 observable 类型为表达异步计算的结构提供了一些局部(甚至全局)最大值。例如: Observable 提供的不是一个,也不是两个,而是 三! 具有不同语义的 monadic 绑定(bind): mergeMap , switchMap , exhaustMap (如果你想知道: concatMap 实际上是 mergeMap 的特例)。这个事实本身就表明 observable 是一个非常有趣的数学结构。

奖金

Observable 被称为流,而流(通常)是 [commonads]​​ ( https://bartoszmilewski.com/2017/01/02/comonads/ )。这是否意味着 observable 不仅是一个单子(monad)而且也是一个共子?

Erik Meijer twit's :

@rix0rrr For a while Rx had a ManySelect operator. Rx is both a monad and a comonad. 144 characters is too short to explain that. Sorry ;-)

关于javascript - RxJS.Observable 是单子(monad)吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51542865/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com