gpt4 book ai didi

scala - 为隐式 Monad 使用 Scala 的定界延续

转载 作者:行者123 更新时间:2023-12-04 02:21:51 25 4
gpt4 key购买 nike

我正在玩某种由单子(monad)接口(interface)定义的 DSL。

由于使用一堆 flatMap 应用程序应用 monad 有点麻烦,而且我发现在语法上理解起来并不那么漂亮,所以我试图使用定界延续来隐式地混合 monadic 和非 monadic 代码。

它实际上工作正常,但我对这些类型真的不满意,因为我必须将自己限制在可编译的类型“Any”:(。因此,稍后在结果是时使用“Any”和“casting”需要可能会导致运行时错误...

这是一些将 Scala 中的 Option-Monad 与常规代码混合的示例代码,因此您可以看到我在说什么:

object BO {

import scala.util.continuations._

def runOption[C](ctx: => Any @cpsParam[Option[Any],Option[Any]]): Option[C] = {
val tmp : Option[Any] = reset {
val x : Any = ctx
Some(x)
}
tmp.asInstanceOf[Option[C]]
}

def get[A](value:Option[A]) = shift { k:(A=>Option[Any]) =>
value.flatMap(k)
}

class CPSOption[A](o:Option[A]) {
def value = get[A](o)
}

implicit def opt2cpsopt[A](o:Option[A]) = new CPSOption(o)

def test1 = runOption[Int] {
val x = get(None)
x
}

def test2 = runOption[Int] {
val x = Some(1).value
x
}

def test3 = runOption[Int] {
val x = Some(1)
val y = Some(2)
x.value + y.value
}

def test_fn(x:Option[Int], y:Option[Int], z:Option[Int]) = runOption[Int] {
x.value * x.value + y.value * y.value + z.value * z.value
}

def test4 = test_fn(Some(1), Some(2), Some(3))

def test5 = test_fn(Some(1), None, Some(3))
}

编译代码:
$ scalac -P:continuations:enable BO.scala

并在 scala REPL 中进行测试:
scala> import BO._
scala> test4
res0: Option[Int] = Some(14)
scala> test5
res1: Option[Int] = None

Option-Monad 使用 运行。运行选项 功能(见测试功能)。在 内部调用的函数运行选项 可以使用 获取 函数或 值(value) 获取值的方法选项 .如果值为 , Monad 将立即停止并返回 .因此不再需要对 类型的值进行模式匹配选项 .

问题是,我必须在 中使用类型“Any”。运行选项 对于 中的延续类型获取 .

是否可以表达 运行选项 获取 在scala中使用rank-n类型?
所以我可以写:
def runOption[C](ctx: forall A . => A @cpsParam[Option[A], Option[C]]) : Option[C] = 
...

def get[A](value:Option[A]) = shift { k:(forall B . A=>Option[B]) =>
value.flatMap(k)
}

谢谢!

最佳答案

Scala 没有更高级别的多态性,尽管您可以通过一些扭曲来模拟它(参见 herehere )。好消息是,这里不需要那种火力。试试这些:

def runOption[A](ctx: => A @cps[Option[A]]): Option[A] = reset(Some(ctx))

def get[A](value:Option[A]) = shift { k:(A=>Option[A]) => value flatMap k }

第二次尝试

好的,让我们再试一次,鉴于您在 runOption 中使用了多个类型的示例堵塞:
object BO {

import scala.util.continuations._

def runOption[A](ctx: => A @cps[Option[A]]): Option[A] = reset(Some(ctx))

def get[A, B](value:Option[A]):A @cps[Option[B]] = shift { k:(A=>Option[B]) =>
value flatMap k
}

class CPSOption[A](o:Option[A]) {
def value[B] = get[A, B](o)
}

implicit def opt2cpsopt[A](o:Option[A]) = new CPSOption[A](o)

def test1 = runOption {
val x = get[Int, Int](None)
x
}

def test2 = runOption {
Some(1).value[Int]
}

def test3 = runOption {
val x = Some(1)
val y = Some(2)
x.value[Int] + y.value[Int]
}

def test_fn(x:Option[Int], y:Option[Int], z:Option[Int]) =
runOption (x.value[Int] * x.value[Int] +
y.value[Int] * y.value[Int] +
z.value[Int] * z.value[Int])

def test4 = test_fn(Some(1), Some(2), Some(3))

def test5 = test_fn(Some(1), None, Some(3))

def test6 = runOption { val x = Some(1)
val y = Some(2)
x.value[Boolean] == y.value[Boolean] }
}

不幸的是,如您所见,结果并不漂亮。由于 Scala 的类型推断能力有限,您需要为 value 的大多数用途提供显式类型参数。 , 并且在任何给定的 runOption block ,对于 value 的每次使用,它始终是相同的类型参数--见 test_fn因为这变得非常可怕。另一方面,您不再需要为 runOption 提供显式类型参数。 block ,但相比之下这是一个很小的胜利。所以这现在是完全类型安全的,但这不是我所说的用户友好,我猜用户友好是这个库的重点。

我仍然坚信 rank-n 类型在这里不适用。如您所见,这里的问题现在是类型重构之一,而 rank-n 类型使重构更加困难,而不是更少!

关于scala - 为隐式 Monad 使用 Scala 的定界延续,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3622944/

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