Scala 3. 将 Haskell 中的 Continuation monad 示例转换为 Scala

huangapple go评论100阅读模式
英文:

Scala 3. Adapting Continuation monad example from Haskell to Scala

问题

  1. 学习Scala 3中的单子主题
  2. https://jsdw.me/posts/haskell-cont-monad/ 上找到了可理解的Continuation单子的分解。
  3. 当我尝试将简单的代码转换成Scala
  4. ```haskell
  5. twoC = \out -> out 2
  6. helloC = \out -> out "hello"
  7. ret val = \out -> out val
  8. inC `bind` fn = \out -> inC (\inCval -> (fn inCval) out)
  9. fourC = twoC `bind` \two -> ret (two*2)
  10. twoHelloC = twoC `bind` \two ->
  11. helloC `bind` \hello ->
  12. ret $ (show two)++hello

我可以编译并且可以很好地运行fourC(identity)。但是twoHelloC中的bind抱怨了Int/String类型不匹配。

我目前的bind实现如下:

  1. val twoCont: (Int => Int) => Int =
  2. out => out(2)
  3. val helloCont: (String => String) => String =
  4. out => out("hello")
  5. type Cont[X, R] = (X => R) => R
  6. extension[A, FinalRes] (inCont: Cont[A, FinalRes]) {
  7. infix def bind[B](fn: A => Cont[B, FinalRes]): Cont[B, FinalRes] = {
  8. (out: B => FinalRes) => inCont(inContVal => (fn(inContVal))(out))
  9. }
  10. }
  11. val twoHelloCont: (String => String) => String =
  12. twoCont bind (two =>
  13. helloCont bind (hello => // 这里看到 Cont[String, String] 很不高兴
  14. return_(two.toString + hello)
  15. )
  16. )

问题:
你会如何在Scala中实现中缀bind,以及为什么Haskell类型系统允许twoHelloC编译?我在这里错过了什么?

谢谢

  1. <details>
  2. <summary>英文:</summary>
  3. Learning Scala 3 with monadic topics.
  4. came across understandable breakdown of Continuation monad at https://jsdw.me/posts/haskell-cont-monad/
  5. When I try to adopt simple code into Scala
  6. ```haskell
  7. twoC = \out -&gt; out 2
  8. helloC = \out -&gt; out &quot;hello&quot;
  9. ret val = \out -&gt; out val
  10. inC `bind` fn = \out -&gt; inC (\inCval -&gt; (fn inCval) out)
  11. fourC = twoC `bind` \two -&gt; ret (two*2)
  12. twoHelloC = twoC `bind` \two -&gt;
  13. helloC `bind` \hello -&gt;
  14. ret $ (show two)++hello

i can have fourC(identity) compiling and working well.
But binds in twoHelloC complain about Int/String type mismatch.

current impl of bind I have:

  1. val twoCont: (Int =&gt; Int) =&gt; Int =
  2. out =&gt; out(2)
  3. val helloCont: (String =&gt; String) =&gt; String =
  4. out =&gt; out(&quot;hello&quot;)
  5. type Cont[X, R] = (X =&gt; R) =&gt; R
  6. extension[A, FinalRes] (inCont: Cont[A, FinalRes]) {
  7. infix def bind[B](fn: A =&gt; Cont[B, FinalRes]): Cont[B, FinalRes] = {
  8. (out: B =&gt; FinalRes) =&gt; inCont(inContVal =&gt; (fn(inContVal))(out))
  9. }
  10. }
  11. val twoHelloCont: (String =&gt; String) =&gt; String =
  12. twoCont bind (two =&gt;
  13. helloCont bind (hello =&gt; // here it is unhappy to see Cont[String, String]
  14. return_(two.toString + hello)
  15. )
  16. )

Question:
how would you implement infix bind in Scala, and why Haskell typesystem permits twoHelloC to compile? What do i miss here?

thanks

答案1

得分: 3

In Scala, you can start with ordinary methods. Here is the translated code:

  1. def twoC[A](out: Int => A): A = out(2)
  2. def helloC[A](out: String => A): A = out("hello")
  3. def ret[A1, A2](value: A1): (A1 => A2) => A2 = func => func(value)
  4. def bind[A1, A2, A3, A4](inC: (A1 => A2) => A3)(fn: A1 => A4 => A2): A4 => A3 =
  5. out => inC(inCval => fn(inCval)(out))
  6. def fourC[A]: (Int => A) => A = bind(twoC[A])(two => ret(two * 2))
  7. def twoHelloC[A]: (String => A) => A =
  8. bind(twoC[A])(two =>
  9. bind(helloC[A])(hello =>
  10. ret(two.toString + hello)
  11. )
  12. )

You can further enhance this code with extension, infix, Cont, and other features as needed. Is it clear how to finish the translation?

英文:

If you have questions what types were inferred in Haskell you can always ask :t ... in ghci

  1. ghci&gt; :t twoHelloC
  2. twoHelloC :: ([Char] -&gt; t) -&gt; t
  3. ghci&gt; :t fourC
  4. fourC :: (Integer -&gt; t) -&gt; t
  5. ghci&gt; :t bind
  6. bind :: ((t1 -&gt; t2) -&gt; t3) -&gt; (t1 -&gt; t4 -&gt; t2) -&gt; t4 -&gt; t3
  7. ghci&gt; :t ret
  8. ret :: t1 -&gt; (t1 -&gt; t2) -&gt; t2
  9. ghci&gt; :t helloC
  10. helloC :: (String -&gt; t) -&gt; t
  11. ghci&gt; :t twoC
  12. twoC :: (Integer -&gt; t) -&gt; t

In Scala you should start with ordinary methods. Verbose translation is

  1. def twoC[A](out: Int =&gt; A): A = out(2)
  2. def helloC[A](out: String =&gt; A): A = out(&quot;hello&quot;)
  3. def ret[A1, A2](`val`: A1): (A1 =&gt; A2) =&gt; A2 =
  4. (out: A1 =&gt; A2) =&gt; out(`val`)
  5. def bind[A1, A2, A3, A4](inC: (A1 =&gt; A2) =&gt; A3)(fn: A1 =&gt; A4 =&gt; A2): A4 =&gt; A3 =
  6. (out: A4) =&gt; inC((inCval: A1) =&gt; fn(inCval)(out))
  7. def fourC[A]: (Int =&gt; A) =&gt; A =
  8. bind[Int, A, A, Int =&gt; A](twoC[A])((two: Int) =&gt; ret[Int, A](two * 2))
  9. def twoHelloC[A]: (String =&gt; A) =&gt; A =
  10. bind[Int, A, A, String =&gt; A](twoC[A])((two: Int) =&gt;
  11. bind[String, A, A, String =&gt; A](helloC[A])((hello: String) =&gt;
  12. ret[String, A](two.toString + hello)
  13. )
  14. )

which can be shortened to

  1. def twoC[A](out: Int =&gt; A): A = out(2)
  2. def helloC[A](out: String =&gt; A): A = out(&quot;hello&quot;)
  3. def ret[A1, A2](`val`: A1): (A1 =&gt; A2) =&gt; A2 = out =&gt; out(`val`)
  4. def bind[A1, A2, A3, A4](inC: (A1 =&gt; A2) =&gt; A3)(fn: A1 =&gt; A4 =&gt; A2): A4 =&gt; A3 =
  5. out =&gt; inC(inCval =&gt; fn(inCval)(out))
  6. def fourC[A]: (Int =&gt; A) =&gt; A = bind(twoC[A])(two =&gt; ret(two * 2))
  7. def twoHelloC[A]: (String =&gt; A) =&gt; A =
  8. bind(twoC[A])(two =&gt;
  9. bind(helloC[A])(hello =&gt;
  10. ret(two.toString + hello)
  11. )
  12. )

Now you can add extension, infix, Cont etc.

Is is clear how to finish translation?

huangapple
  • 本文由 发表于 2023年2月24日 14:05:24
  • 转载请务必保留本文链接:https://go.coder-hub.com/75553113.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定