Scala中类似于Haskell do-notation或F# Computation Expressions的等效方式是什么?

7

F#计算表达式可以通过浓厚的语法糖层来隐藏单子语法的复杂性。Scala中是否有类似的东西可用?

我认为是for推导式...

例如:

val f = for {
  a <- Future(10 / 2) // 10 / 2 = 5
  b <- Future(a + 1)  //  5 + 1 = 6
  c <- Future(a - 1)  //  5 - 1 = 4
 } yield b * c         //  6 * 4 = 24

 val result = f.get

但这样做并不太合适。有更好的语法吗?
例如在Haskell中,你可以这样写:
    main = do fromHandle <- getAndOpenFile "Copy from: " ReadMode
              toHandle   <- getAndOpenFile "Copy to: " WriteMode 
              contents   <- hGetContents fromHandle
              hPutStr toHandle contents
              hClose toHandle
              putStr "Done."
与Scala不同,这个看起来不像是循环。Scala语法似乎与List comprehension耦合过强,这是一个独立的概念。这阻止我编写内部DSL(单子)的形式不奇怪。

4
for 推导式是正确的。在幕后,它们被展开为 mapflatMap,这正是 Haskell 中 do 表示法的工作方式(除了在 Haskell 中这些方法被称为 fmap>>=)。 - Tom Crockett
5
@Dan Burton - 这个问题已经被问过并回答了几次...我会向你推荐这个优秀的答案:https://dev59.com/xnNA5IYBdhLWcg3wNa6T#1059501 - Tom Crockett
1
对我第一条评论的更正... 在Haskell中,do-notation的desugaring实际上并没有使用fmap,因为没有yield语句需要它(而且我们不能确定所有的Monad都是Functor,尽管它们应该是)... 代替关键字yield,你只需使用return函数,当在do块中作为最后一条语句调用时,相当于一个fmap - Tom Crockett
1
符号表示法有什么让人感觉不对劲的地方吗? - Daniel C. Sobral
1
我们当然可以一直争论下去,但这并不会改变大多数人将"for"与循环联系在一起的事实,而且这种联系是有充分的理由的。是的,可能有办法"克服它",但这并没有真正改变问题的核心。 - Erik Kaplun
显示剩余7条评论
2个回答

4
缺少的一块可能是在Scala的for-comprehension中使用=的问题:
val f = for {
  a <- Future(10 / 2) // 10 / 2 = 5
  b <- Future(a + 1)  //  5 + 1 = 6
  c <- Future(a - 1)  //  5 - 1 = 4
  d = b * c           //  6 * 4 = 24
} yield d


val result = f.get

通过合理地混合使用<-=,您应该拥有所需的所有灵活性。


1
有时候我希望Haskell的do语法可以从使用=推断出let - Dan Burton

-2

看起来在Scala中没有这样的语法可用,我们需要使用编译器插件架构自己实现它。


我考虑过使用宏 - 你有没有考虑过? - Erik Kaplun

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接