0

主に文字列、int、double など、さまざまなタイプの Scala の値のリストがあります。これらの値の一部は null の場合があります。これは と考えることができますList[Option[AnyRef]]。このリストの各値について、存在する場合は、括弧内の値を含む文字列を生成したいと考えています。存在しない場合は、空の文字列になります。さらに、値を括弧の間に挿入する前に、変換を適用する必要がある場合があります。たとえば、値が の場合Option[String]、関数を適用したいと思うかもしれませんtrim

私は、データ構造をオプションの値のマップと考え、その値を操作して文字列を返すオプションの関数と考えることで、これに取り組みました (私は Map[Option [A], Option[(A) => String]] は正しくありません。すべてのオプション キーが同じ型であることを意味します)。これまでにサンプルデータと関数を使用して書いたものは次のとおりです。

lazy val messageContext = Map(
  None -> None,
  Some("hello") -> None,
  Some(4) -> Some(negate _),
  None -> None
) map { t => wrapText(t._1, t._2)  } toList

private def wrapText[A](option: Option[A], transFn: Option[(A) => String]): String = option match {
  case Some(o) => " (%s)".format(transFn.getOrElse(stringIdentity _)(o))
  case _ => ""
}

private def stringIdentity[A](a: A) = a.toString

private def negate(n: Number) = n * -1

ただし、コンパイラ エラーが発生します。

error: type mismatch;
 found   : Option[java.lang.Number => java.lang.String]
 required: Option[AnyVal{def getClass(): java.lang.Class[_ >: Double with Int <: AnyVal]} => String]
  ) map { t => wrapText(t._1, t._2)  } toList

私のアプローチはこれに近いですか?これは Scala で簡単に実現できますか? それとも、これを実際に機能させるには、いくつかの scalaz マジックに頼る必要がありますか?

ありがとう。

編集:上記の入力の正しい出力は次のようになります。 List[""," (hello)"," (-4)",""]

4

2 に答える 2

2

魔法は必要ありません。これがあなたの望むものかどうかは正確にはわかりませんが、もう一度言います

  • None入力は ""出力を意味する
  • Some(v)入力は" (%s)".format(trans(v))出力を意味します。ここで、transは値のオプションの変換です

元:

val input = List(None, Some("hello"), Some(4), None)

def trans(v: Any) = v match {
   case num @ 4 => -num
   case _       => v  // identity
}

val output = input.map {
   case Some(v) => " (%s)".format(trans(v))
   case _       => ""
}
于 2013-01-18T20:19:04.253 に答える
0

ここでの最初の問題は、 aMap[A,B]にはマップ全体に対して 2 つの型パラメーターがあり、各 に対していくつかの型パラメーターがないことtupleです。は、キーと値の最も一般的な先祖を型パラメーターとして受け取るMapため、を使用して実行することはできません。Map

scala>  import StackOverflowTest

StackOverflowTest.messageContext
import StackOverflowTest

scala> res0: scala.collection.immutable.Map[Option[java.lang.Comparable[_ >: java.lang.Integer with java.lang.String <: java.lang.Comparable[_ >: java.lang.Integer with java.lang.String <: java.lang.Comparable[_ >: java.lang.Integer with java.lang.String <: java.io.Serializable] with java.io.Serializable] with java.io.Serializable] with java.io.Serializable],Option[java.lang.Integer => Int]] = Map(None -> None, Some(hello) -> None, Some(4) -> Some(<function1>))

scala> 

異なるタイプのタプルをマップまたはシーケンスに配置すると、各タプルに関するタイプ情報が失われ、最初の共通の親のみが保持されます。Tuple2[A,B]それぞれが異なるタプルのマップを保持できるデータ構造が必要な場合はA,B、Shapeless レコードや HList などのより動的な構造が必要です。

https://github.com/milessabin/shapeless

ここでの 2 番目の問題は、Number * 1 のセマンティクスが Java で定義されていないことです。必要な数値のサブタイプ (java.lang.Integer など) を使用する必要があります。

3 番目の問題は、wrapText がtransFn: Option[(A) => String])negate の出力値の型が String ではないときに a を必要とすることです (実際には、Java クラス Number に対して * が定義されていません)。以下だけをコンパイルしようとすると、その部分を取り除き、Mapネゲートメソッドを修正します。

  private def wrapText[A](option: Option[A], transFn: Option[(A) => String]): String = option match {
    case Some(o) => " (%s)".format(transFn.getOrElse(stringIdentity _)(o))
    case _ => ""
  }

  private def stringIdentity[A](a: A) = a.toString

  private def negate(n: java.lang.Integer) = n * -1

  wrapText(Some(4),negate _ )

これはエラーでコンパイルされません:

error: type mismatch;
found   : Option[java.lang.Integer => Int]
required: Option[? => String]
wrapText(Some(4),Some(negate _) )

ネゲートを最終的に文字列を返すように修正すると、最後の壁にぶつかります

error: type mismatch;
found   : Option[java.lang.Integer => java.lang.String]
required: Option[Int => String]
wrapText(Some(4),Option(negate _) )

ここでの問題は、Scala と Java が自動ボックス化とボックス化解除を実行する一方で、型パラメーターの自動変換を実行しないことです: Option[Int=> String] is not of the same class as Option[java.lang.Integer=>String] 、したがって、最初のオプションのタイプを強制して、正しくコンパイルする必要があります。

  wrapText(Some(4:java.lang.Integer),Some(negate _) )
于 2013-01-18T20:26:59.123 に答える