簡體   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