5

次のScalaの問題があります。

HList のリストを取得する関数を作成する

List(23 :: “a” :: 1.0d :: HNil, 24 :: “b” :: 2.0d :: HNil)    # this is list of hlists

リストの HList を返します

List[Int](23, 24) :: List[String](“a”, “b") :: List[Double](1.0d, 2.0d) :: HNil # this is hlist of lists

これは、一般的な unzipN のようなものです。任意の HList はまったく可能ですか?

ありがとうございました。

4

2 に答える 2

6

この問題を解決するには多くの方法があり、(Nikita の回答のように) カスタム型クラスを定義することは完全に良い方法です。ただし、個人的には、次のアプローチの方が少し明確だと思います。まず、モノイドで構成された異種リストをモノイドにしましょう:

import shapeless._
import scalaz._, Scalaz._

implicit object hnilMonoid extends Monoid[HNil] {
  val zero = HNil
  def append(f1: HNil, f2: => HNil) = HNil
}

implicit def hconsMonoid[H: Monoid, T <: HList: Monoid] = new Monoid[H :: T] {
  val zero = Monoid[H].zero :: Monoid[T].zero
  def append(f1: H :: T, f2: => H :: T) =
    (f1.head |+| f2.head) :: (f1.tail |+| f2.tail)
}

私はScalazのを使用してMonoidいますが、独自のものを簡単に書くこともできます — これは、型が恒等要素との加算のような操作を行うことを証明する型クラスにすぎません。この例のリスト (あらゆるもの) で重要なのは、連結されたモノイドであり、空のリストが恒等要素であることです。

次は、与えられたものをリストにラップする単純な多相関数です。

object singleton extends Poly1 { implicit def anything[A] = at[A](List(_)) }

そして、すべてを結び付けます。

def unzipN[L <: HList, Out <: HList](hlists: List[L])(implicit
  mapper: ops.hlist.Mapper.Aux[singleton.type, L, Out],
  monoid: Monoid[Out]
): Out = hlists.map(_ map singleton).suml

これで、例を定義できます。

val myList = List(23 :: "a" :: 1.0d :: HNil, 24 :: "b" :: 2.0d :: HNil)

これで完了です。

scala> println(unzipN(myList))
List(23, 24) :: List(a, b) :: List(1.0, 2.0) :: HNil

このアプローチでは、機械のほとんどが非常に一般的であり、各ステップが何をするかを直感的に理解するのは簡単です。次の簡単な例を考えてみましょう。

val simple = List(1 :: "a" :: HNil, 2 :: "b" :: HNil)

simple.map(_ map singleton)は次のとおりです。

List(List(1) :: List("a") :: HNil, List(2) :: List("b") :: HNil)

List[Int] :: List[String] :: HNilしかし、上部にあるモノイド機構のおかげで、 型のものを「追加」する方法を知っています。したがって、Scalaz の を使用してリストの合計を取得するだけで済みsumlます。

これはすべて Shapeless 2.0 を使用していますが、1.2 でもかなり似ています。

于 2014-01-29T22:46:17.603 に答える