まず、引用元のプログラムのシンタックスシュガーを除去すると以下のようになります。
import net.liftweb.json.JsonParser.parse
import net.liftweb.json.JsonAST._
val json_str = """{"a":1,"b":2,"c":3}"""
val list = parse(json_str).filter{
case JObject(_) => true; case _ => false
}.flatMap{
case JObject(child) => child.map{item => (item.values)}
}
list.foreach(println _)
このとき、item.valuesの型は(String, item.value.Values)型になりますが(このように、変数に依存する型を
Scalaではパス依存型といいます)、flatMap[B]の型パラメータBを推論するのにitemを使用することができないので(
itemはスコープを抜けているため)、コンパイラはその代わりにitemの型であるJFieldを
使用してB = (String, JField#value.Values)(JField#value.Valuesはプログラム上では表記不可能な型)
と推論しているようです。そして、この型とitem.valuesの型である(String, item.value.Values)型が非互換である
ため、型チェッカにはねられてしまうようです。正直言って自分もこの辺り(パス依存型)の動作は完全に理解できてない
ので、間違っている可能性もありますが…。
とりあえず、簡単な対策としては、items.valueを(String, JValue#Values)型にアップキャストして以下のように
してやるとコンパイルを通るようになります。
# 正直なところ、JField#Valuesの型を(String, value.Values)から
# (String, JValue#Values)に変更してもらえれば、それが一番良いような気がしていますが…
import net.liftweb.json.JsonParser.parse
import net.liftweb.json.JsonAST._
val json_str = """{"a":1,"b":2,"c":3}"""
val list = for {
JObject(child) <- parse(json_str)
item <- child
} yield (item.values:(String, JValue#Values))
list.foreach(println _)
2009年12月16日18:40 関隆 <hawk...@gmail.com>:
> --
>
> このメールは Google グループのグループ「scala-be」の登録者に送られています。
> このグループに投稿するには、scal...@googlegroups.com にメールを送信してください。
> このグループから退会するには、scala-be+u...@googlegroups.com にメールを送信してください。
> 詳細については、http://groups.google.com/group/scala-be?hl=ja からこのグループにアクセスしてください。
>
>
>
--
Kota Mizushima
e-mail: hau5...@tree.odn.ne.jp,mizu...@gmail.com
2009年12月16日23:55 関隆 <hawk...@gmail.com>:
> 水島さんへ
>
> こんばんは、関隆です。
>
> ご返事ありがとうございます。
>
> あまりちゃんとは調べてませんが、
> とりあえず、Tracに新しいTicketを投稿してみました。
おお。どうもありがとうございます。
>
> 詳しい説明もありがとうございます。
> なんとなくは理解できましたが、勉強不足を痛感しました。(^^;
> 特に「パス依存型」というのは今回が初耳でした。
> Scalaは本当に型に関して奥深いですねぇ・・・
>
> 1点、 JValue#Valuesというのは、単純に
> 「JValue クラスで定義されているValues型」
> という意味で良いのでしょうか。
そういう理解で良いと思います。T1#T2のように書いた場合(type projectionと呼びます)、
単にT1のメンバであるT2の型という意味になります(Javaの
T1.T2と同じ意味ですね)。一方、t1.T2(t1は型ではなく値で、t1の型はT1とする)の
場合、変数t1が指しているオブジェクトのメンバである型T2という
意味になります。前者の場合、どのT2であっても、T1#T2型の変数に
代入できますが、後者の場合、t1のインスタンスから生成されたT2型しか
t1.T2型に代入できない点が異なります。
おはようございます、関隆です。
解説ありがとうございます。
>前者の場合、どのT2であっても、T1#T2型の変数に
> 代入できますが、後者の場合、t1のインスタンスから生成されたT2型しか
> t1.T2型に代入できない点が異なります。
なるほど、これで、
>>> # 正直なところ、JField#Valuesの型を(String, value.Values)から
>>> # (String, JValue#Values)に変更してもらえれば、それが一番良いような気がしていますが…
の言わんとしていることが理解できました。
ありがとうございました。
ちなみに、登録したバグレポートは
https://lampsvn.epfl.ch/trac/scala/ticket/2804
これです。
自動翻訳を使っているので英語的にはおかしい可能性大ですが、
まぁ、意味は通じるでしょう・・・(^^;
2009年12月17日2:26 Kota Mizushima <mizu...@gmail.com>:
こんにちは、関隆です。
質問ばかりで恐縮です。もう2点だけ・・・
直感的には動作がわかったためサラッと流してしまっていて、
実はよくわかっていなかった点なんですが、
1:
>>>> } yield (item.values:(String, JValue#Values))
の行の
「:(String, JValue#Values)」
の部分は、
言語仕様
http://www.scala-lang.org/docu/files/ScalaReference.pdf
の、80ページにある。
6.13 Typed Expressions
Expr1 ::= PostfixExpr ‘:’ CompoundType
を利用しているとの理解でよいでしょうか。
2:
この部分、今回の場合は
} yield (item.values.asInstanceOf[(String, JValue#Values)])
と置き換えても動くようですが、
asInstanceOfとの違いをどう理解するのが良いのでしょうか。
どうぞよろしくお願いいたします。
2009年12月17日9:46 関隆 <hawk...@gmail.com>:
水島です。
2009年12月17日16:55 関隆 <hawk...@gmail.com>:
> 水島さんへ
>
> こんにちは、関隆です。
>
> 質問ばかりで恐縮です。もう2点だけ・・・
>
> 直感的には動作がわかったためサラッと流してしまっていて、
> 実はよくわかっていなかった点なんですが、
>
> 1:
> >>>> } yield (item.values:(String, JValue#Values))
> の行の
> 「:(String, JValue#Values)」
> の部分は、
>
> 言語仕様
> http://www.scala-lang.org/docu/files/ScalaReference.pdf
> の、80ページにある。
> 6.13 Typed Expressions
> Expr1 ::= PostfixExpr ‘:’ CompoundType
> を利用しているとの理解でよいでしょうか。
はい。その部分で合っています。
>
> 2:
> この部分、今回の場合は
> } yield (item.values.asInstanceOf[(String, JValue#Values)])
> と置き換えても動くようですが、
>
> asInstanceOfとの違いをどう理解するのが良いのでしょうか。
・asInstanceOfは無理矢理型を変換するため、型安全ではない(型を変換した
後に妙な動作(ClassCastExceptionを含む)が起きる可能性がある)
のに対して、
・expr:typeは、exprがtypeに変換できない(この変換というのは、implicit conversionによるものも
含みます)場合はコンパイル時に型エラーが出るため、型安全である
というのが大きな違いです。
こんばんは、関隆です。
解説ありがとうございます。
なるほど、良く分かりました。
ありがとうございました。
2009年12月17日19:30 Kota Mizushima <mizu...@gmail.com>: