Scalaでは `#`演算子はどういう意味ですか?


131

このコードはこのブログにあります:Scalaでの型レベルのプログラミング

// define the abstract types and bounds
trait Recurse {
  type Next <: Recurse
  // this is the recursive function definition
  type X[R <: Recurse] <: Int
}
// implementation
trait RecurseA extends Recurse {
  type Next = RecurseA
  // this is the implementation
  type X[R <: Recurse] = R#X[R#Next]
}
object Recurse {
  // infinite loop
  type C = RecurseA#X[RecurseA]
}

#コードには、R#X[R#Next]私が見たことのない演算子があります。それを検索するのは難しいので(検索エンジンでは無視されます)、それが何を意味するのか誰が教えてくれますか?


1
「ポンド記号」は「オクタスロップ」と呼ばれることもあります(Google検索でこのページが表示されました)。
philwalk 2016年


#+や#-などの他の演算子についてはどうですか(github.com/tpolecat/doobie/blob/series/0.4.x/yax/h2/src/main/…を参照)?包括的なリストはありますか?
Markus Barthlen 2017

回答:


240

それを説明するには、まずScalaのネストされたクラスを説明する必要があります。この簡単な例を考えてみましょう:

class A {
  class B

  def f(b: B) = println("Got my B!")
}

それを使って何かを試してみましょう:

scala> val a1 = new A
a1: A = A@2fa8ecf4

scala> val a2 = new A
a2: A = A@4bed4c8

scala> a2.f(new a1.B)
<console>:11: error: type mismatch;
 found   : a1.B
 required: a2.B
              a2.f(new a1.B)
                   ^

Scalaで別のクラスの内部でクラスを宣言すると、そのクラスの各インスタンスにそのようなサブクラスがあることになります。つまり、A.Bクラスはありませんがa1.Ba2.Bクラスがあり、エラーメッセージが上記のように異なるクラスです。

それを理解していない場合は、パスに依存するタイプを調べてください。

これ#により、特定のインスタンスに制限することなく、そのようなネストされたクラスを参照できるようになります。言い換えれば、何もありませんA.Bが、そこだA#Bことを意味する、Bの入れ子になったクラスの任意のインスタンスをA

上記のコードを変更することで、これを確認できます。

class A {
  class B

  def f(b: B) = println("Got my B!")
  def g(b: A#B) = println("Got a B.")
}

そしてそれを試す:

scala> val a1 = new A
a1: A = A@1497b7b1

scala> val a2 = new A
a2: A = A@2607c28c

scala> a2.f(new a1.B)
<console>:11: error: type mismatch;
 found   : a1.B
 required: a2.B
              a2.f(new a1.B)
                   ^

scala> a2.g(new a1.B)
Got a B.

素晴らしい例です。私はそれがそのように機能することを完全に受け入れますが、これを理解するのは難しいです:scala> classOf [A#B] res7:Class [A#B] = class A $ B scala> classOf [aB] res8:Class [aB] = class A $ B。つまり、実際には同じタイプです。
カイロン

2
それらの値は同じ文字列表現を持ち、それらは等しい場合さえあります。ClassJavaクラスのランタイム表現であり、Javaでも制限されています。たとえば、List<String>List<Integer>同じランタイムを持っていますClass。場合Class表現するための豊富なだけでは不十分であるのJava型が表すとき、それはほとんど役に立たないのですScalaの型を。この場合res7: Class[A#B] = class A$Bも、等号の左側は型であり、クラスのJava ランタイム表現である値の場合は等号の右側です。
Daniel C. Sobral 2016年

13

タイププロジェクションと呼ばれ、タイプメンバーへのアクセスに使用されます。

scala> trait R {
     |   type A = Int
     | }
defined trait R

scala> val x = null.asInstanceOf[R#A]
x: Int = 0

6
これは答えではありません。これは基本的に、質問と同じコードをわずかに短縮して示しています。たとえば、ポイント表記との違いは何ですか?#これを実際のコードのどこで使用しますか?
notan3xit

2
@ notan3xit多分それはあなたが尋ねようとしていたことに対する答えではありません。しかし、あなたが尋ねたのは「私は今まで見たことがない...それを検索するのは難しいので(検索エンジンでは無視されます)、それが何を意味するのか誰が教えてくれるのですか?」
nafg


弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.