英文:
Scala 3. Adapting Continuation monad example from Haskell to Scala
问题
学习Scala 3中的单子主题。
在 https://jsdw.me/posts/haskell-cont-monad/ 上找到了可理解的Continuation单子的分解。
当我尝试将简单的代码转换成Scala时
```haskell
twoC = \out -> out 2
helloC = \out -> out "hello"
ret val = \out -> out val
inC `bind` fn = \out -> inC (\inCval -> (fn inCval) out)
fourC = twoC `bind` \two -> ret (two*2)
twoHelloC = twoC `bind` \two ->
helloC `bind` \hello ->
ret $ (show two)++hello
我可以编译并且可以很好地运行fourC(identity)
。但是twoHelloC
中的bind
抱怨了Int/String类型不匹配。
我目前的bind
实现如下:
val twoCont: (Int => Int) => Int =
out => out(2)
val helloCont: (String => String) => String =
out => out("hello")
type Cont[X, R] = (X => R) => R
extension[A, FinalRes] (inCont: Cont[A, FinalRes]) {
infix def bind[B](fn: A => Cont[B, FinalRes]): Cont[B, FinalRes] = {
(out: B => FinalRes) => inCont(inContVal => (fn(inContVal))(out))
}
}
val twoHelloCont: (String => String) => String =
twoCont bind (two =>
helloCont bind (hello => // 这里看到 Cont[String, String] 很不高兴
return_(two.toString + hello)
)
)
问题:
你会如何在Scala中实现中缀bind
,以及为什么Haskell类型系统允许twoHelloC
编译?我在这里错过了什么?
谢谢
<details>
<summary>英文:</summary>
Learning Scala 3 with monadic topics.
came across understandable breakdown of Continuation monad at https://jsdw.me/posts/haskell-cont-monad/
When I try to adopt simple code into Scala
```haskell
twoC = \out -> out 2
helloC = \out -> out "hello"
ret val = \out -> out val
inC `bind` fn = \out -> inC (\inCval -> (fn inCval) out)
fourC = twoC `bind` \two -> ret (two*2)
twoHelloC = twoC `bind` \two ->
helloC `bind` \hello ->
ret $ (show two)++hello
i can have fourC(identity)
compiling and working well.
But bind
s in twoHelloC
complain about Int/String type mismatch.
current impl of bind I have:
val twoCont: (Int => Int) => Int =
out => out(2)
val helloCont: (String => String) => String =
out => out("hello")
type Cont[X, R] = (X => R) => R
extension[A, FinalRes] (inCont: Cont[A, FinalRes]) {
infix def bind[B](fn: A => Cont[B, FinalRes]): Cont[B, FinalRes] = {
(out: B => FinalRes) => inCont(inContVal => (fn(inContVal))(out))
}
}
val twoHelloCont: (String => String) => String =
twoCont bind (two =>
helloCont bind (hello => // here it is unhappy to see Cont[String, String]
return_(two.toString + hello)
)
)
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:
def twoC[A](out: Int => A): A = out(2)
def helloC[A](out: String => A): A = out("hello")
def ret[A1, A2](value: A1): (A1 => A2) => A2 = func => func(value)
def bind[A1, A2, A3, A4](inC: (A1 => A2) => A3)(fn: A1 => A4 => A2): A4 => A3 =
out => inC(inCval => fn(inCval)(out))
def fourC[A]: (Int => A) => A = bind(twoC[A])(two => ret(two * 2))
def twoHelloC[A]: (String => A) => A =
bind(twoC[A])(two =>
bind(helloC[A])(hello =>
ret(two.toString + hello)
)
)
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
ghci> :t twoHelloC
twoHelloC :: ([Char] -> t) -> t
ghci> :t fourC
fourC :: (Integer -> t) -> t
ghci> :t bind
bind :: ((t1 -> t2) -> t3) -> (t1 -> t4 -> t2) -> t4 -> t3
ghci> :t ret
ret :: t1 -> (t1 -> t2) -> t2
ghci> :t helloC
helloC :: (String -> t) -> t
ghci> :t twoC
twoC :: (Integer -> t) -> t
In Scala you should start with ordinary methods. Verbose translation is
def twoC[A](out: Int => A): A = out(2)
def helloC[A](out: String => A): A = out("hello")
def ret[A1, A2](`val`: A1): (A1 => A2) => A2 =
(out: A1 => A2) => out(`val`)
def bind[A1, A2, A3, A4](inC: (A1 => A2) => A3)(fn: A1 => A4 => A2): A4 => A3 =
(out: A4) => inC((inCval: A1) => fn(inCval)(out))
def fourC[A]: (Int => A) => A =
bind[Int, A, A, Int => A](twoC[A])((two: Int) => ret[Int, A](two * 2))
def twoHelloC[A]: (String => A) => A =
bind[Int, A, A, String => A](twoC[A])((two: Int) =>
bind[String, A, A, String => A](helloC[A])((hello: String) =>
ret[String, A](two.toString + hello)
)
)
which can be shortened to
def twoC[A](out: Int => A): A = out(2)
def helloC[A](out: String => A): A = out("hello")
def ret[A1, A2](`val`: A1): (A1 => A2) => A2 = out => out(`val`)
def bind[A1, A2, A3, A4](inC: (A1 => A2) => A3)(fn: A1 => A4 => A2): A4 => A3 =
out => inC(inCval => fn(inCval)(out))
def fourC[A]: (Int => A) => A = bind(twoC[A])(two => ret(two * 2))
def twoHelloC[A]: (String => A) => A =
bind(twoC[A])(two =>
bind(helloC[A])(hello =>
ret(two.toString + hello)
)
)
Now you can add extension
, infix
, Cont
etc.
Is is clear how to finish translation?
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论