繁体   English   中英

ZipList与Scalaz

[英]ZipList with Scalaz

假设我有一个数字列表和一个函数列表:

val xs: List[Int] = List(1, 2, 3)
val fs: List[Int => Int] = List(f1, f2, f3)

现在,我想使用Applicativef1应用于1f2应用于2 ,等等。

val ys: List[Int] = xs <*> fs // expect List(f1(1), f2(2), f3(3))

我如何用Scalaz做到这Scalaz

zip列表的pure永远重复该值,因此无法为Scala的List (或类似list的东西)定义一个zippy应用实例。 Scalaz确实为Stream和适当的zippy应用实例提供了一个Zip标签,但据我所知它仍然很残破。 例如,这将不起作用(但应该):

import scalaz._, Scalaz._

val xs = Tags.Zip(Stream(1, 2, 3))
val fs = Tags.Zip(Stream[Int => Int](_ + 3, _ + 2, _ + 1))

xs <*> fs

您可以直接使用应用实例(如在其他答案中所示),但是拥有语法很好,并且编写“真实的”(即未标记的)包装并不难。 例如,这是我使用的解决方法:

case class ZipList[A](s: Stream[A])

import scalaz._, Scalaz._, Isomorphism._

implicit val zipListApplicative: Applicative[ZipList] =
  new IsomorphismApplicative[ZipList, ({ type L[x] = Stream[x] @@ Tags.Zip })#L] {
    val iso =
      new IsoFunctorTemplate[ZipList, ({ type L[x] = Stream[x] @@ Tags.Zip })#L] {
        def to[A](fa: ZipList[A]) = Tags.Zip(fa.s)
        def from[A](ga: Stream[A] @@ Tags.Zip) = ZipList(Tag.unwrap(ga))
      }
    val G = streamZipApplicative
  }

接着:

scala> val xs = ZipList(Stream(1, 2, 3))
xs: ZipList[Int] = ZipList(Stream(1, ?))

scala> val fs = ZipList(Stream[Int => Int](_ + 10, _ + 11, _ + 12))
fs: ZipList[Int => Int] = ZipList(Stream(<function1>, ?))

scala> xs <*> fs
res0: ZipList[Int] = ZipList(Stream(11, ?))

scala> res0.s.toList
res1: List[Int] = List(11, 13, 15)

就其价值而言,看来这已经被打破了至少两年了

我看到了streamZipApplicative的解决方案:

import scalaz.std.stream._
import scalaz.Tags

val xs: List[Int] = List(1, 2, 3)
val fs: List[Int => Int] = List(f1, f2, f3)

val zippedLists = streamZipApplicative.ap(Tags.Zip(xs.toStream)) (Tags.Zip(fs.toStream))

val result = Tag.unwrap(zippedLists).toList

学习Scalaz在介绍Applicatives时在此主题上花了几段。 他们引用LYAHFGG

但是,[(+ 3),( 2)] < > [1,2]也可以这样工作:将左侧列表中的第一个函数应用于右侧的第一个值,然后应用第二个函数到第二个值,依此类推。 这将导致具有两个值的列表,即[4,4]。 您可以将其视为[1 + 3,2 * 2]。

但随后添加:

这可以在Scalaz中完成,但不容易。

“不容易”部分使用streamZipApplicative就像@ n1r3的答案一样:

scala> streamZipApplicative.ap(Tags.Zip(Stream(1, 2)))(Tags.Zip(Stream({(_: Int) + 3}, {(_: Int) * 2})))
res32: scala.collection.immutable.Stream[Int] with Object{type Tag = scalaz.Tags.Zip} = Stream(4, ?)

scala> res32.toList
res33: List[Int] = List(4, 4)

“不容易”是困扰我的部分。 我想向@Travis Brown借个很棒的答案。 他正在比较monad和应用程序的用法(即为什么在有monad的情况下使用应用程序的用法):

其次(以及相关),使用最不强大的抽象来完成工作只是一种可靠的开发实践。

因此,我要说的是,直到框架提供一个类似于第一个用例的应用程序为止:

val ys: List[Int] = xs <*> fs

要在此处使用zipmap ,请执行以下操作:

xs.zip(fs).map(p=>p._2.apply(p._1))

对我来说,此代码比scalaz中的替代代码更清晰,更简单。 这是完成工作的最不强大的抽象。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM