如何在Scala 3和Cats中实现类似的Haskell函数?
ghci> (+) <$> (+1) <*> (+1) $ 10
22
字符串
有一个使用mapN
的解决方案。这里提到了Using functions as applicative functors/cartesians,但我想要一个使用<*>
而不是mapN
的解决方案。我尝试了类似的方法,但无法编译
import cats._
import cats.implicits._
type Func1[Y] = Int => Y
val add1: Func1[Int] = (x: Int) => x + 1
val addXY: Func1[Func1[Int]] = (x: Int) => (y: Int) => x + y
val foo: Func1[Func1[Func1[Int]]] = Applicative[Func1].pure(addXY)
val bar: Func1[Func1[Int]] = Applicative[Func1].pure(add1)
val foobar = foo <*> bar
foobar(10) // should be 22 but it can't compile
型
请多指教。谢谢
1条答案
按热度按时间xiozqbni1#
Scala Cats允许函数作为
Applicative
示例,就像Haskell一样。字符串
我们可以在Scala中将这些函数编写为
型
现在
<*>
的工作方式和Haskell中的一样,但是<$>
并不作为中缀存在(尤其是因为$
在基于JVM的语言中不是符号字符)。请记住,f <$> x
只是等价于fmap f x
,或者(根据Applicative
定律)pure f <*> x
。所以我们可以写
型
现在,虽然Cats没有提供我所知道的中缀
<$>
,但我们可以很容易地自己编写一个作为扩展方法。我们不能将其命名为<$>
,因为美元符号在JVM上很有趣,但我们可以编写<@>
。型
现在我们可以说
型
完整示例:
型
Scala 2
以上所有内容都是在Scala 3中编写的。如果您使用的是Scala 2,那么您必须做一些复杂的工作才能使Scala按照您想要的方式处理函数。正如您已经看到的,您必须编写
type
别名才能获得正确的类型级泛型行为(例如,如果你想调用pure
)。def
函数必须显式转换为后缀为_
的函数。extension
方法需要是老式的implicit class
。所以总的来说,这是用Scala 2编写的同一个程序。
型