2011-11-24 14 views
6

Scalaの関数は、FunctionNのいずれかの特性を実装するオブジェクトです。例:by-nameパラメータを取る関数を表すFunctionN特性とは何ですか?

scala> def f(x: Int) = x * x 
f: (x: Int)Int 

scala> val ff = f _ 
ff: Int => Int = <function1> 

scala> val fff: Function1[Int, Int] = f _ 
fff: Int => Int = <function1> 

これまでのところ、とても良いです。しかし、名前によるパラメータを取る関数があればどうでしょうか?それは確かにまだFunctionN特徴の一つを実装ん:

scala> def g(x: => Int) = x * x 
g: (x: => Int)Int 

scala> val gg = g _ 
gg: => Int => Int = <function1> 

scala> gg.isInstanceOf[Function1[_, _]] 
res0: Boolean = true 

しかし、どのようなタイプは、それがまさに、ありますか?

scala> val ggg: Function1[Int, Int] = g _ 
<console>:8: error: type mismatch; 
found : => Int => Int 
required: Int => Int 
     val ggg: Function1[Int, Int] = g _ 
            ^

また、それはFunction1[Function0[Int], Int]次のとおりです:それはFunction1[Int, Int]ではありません

scala> val ggg: Function1[Function0[Int], Int] = g _ 
<console>:8: error: type mismatch; 
found : => Int => Int 
required:() => Int => Int 
     val ggg: Function1[Function0[Int], Int] = g _ 
               ^

そしてFunction1[=> Int, Int]はコンパイルに失敗します。

scala> val ggg: Function1[=> Int, Int] = g _ 
<console>:1: error: identifier expected but '=>' found. 
     val ggg: Function1[=> Int, Int] = g _ 
         ^

だから、それは何ですか?

答えて

4

名前の型は非常に便利ですが、タイプの外では安全ではありませんem

スカラーby-nameパラメーターは、遅延評価が必要なときにコードを読みやすくするための構文的な砂糖です。それがなければ、怠け者になる必要のあるものすべての前に "()=>"を置く必要があります。つまり、実行時にはfunction0にすぎませんが、パラメータ以外のものを名前型のものとして定義することができれば、タイピングシステムレベルで問題になります。 FunctionNの特性は、JavaとJVMの関数型のようなものがないため、主に実装とJavaの相互運用性のためにあります。

なので、明示的な

あなたは以下のように入力すると、あなたが制限できるようになります

def g(x: => Int) = x * x 
val ggg: (=> Int) => Int = g _ 

より複雑なタイピング

ザ・-名前でで明示的に指定する必要がある場合typingは、関数型宣言のパラメータ部分内でのみ使用できます。関数型自体は、他のパラメータ化された型の内部で使用できます。

var funks: List[(=> Int) => Int] = Nil 
funks ::= ggg 
funks foreach { _ { println("hi"); 5 } } 
1

this questionへのRex Kerrの回答により、最終的にはby-name引数がFunction0に変換されますが、おそらくコンパイル時に特に扱われます。あなたがこの確認できます

:私の最初のコメントに拡張するために

scala> gg(sys.error("me")) 
java.lang.RuntimeException: me 
    at scala.sys.package$.error(package.scala:27) 
    at $anonfun$1.apply(<console>:10) 
    at $anonfun$1.apply(<console>:10) 
    at scala.Function0$class.apply$mcI$sp(Function0.scala:34) 
    at scala.runtime.AbstractFunction0.apply$mcI$sp 
    ... 

EDIT

を、これはまた、あなたが名前によるパラメータのタイプを与えることができないことを示します。

def test[A: Manifest](fun: Function1[A, Int]): Unit = 
    println("Found " + implicitly[Manifest[A]]) 

scala> test(gg) 
<console>:11: error: No Manifest available for => Int. 
       test(gg) 
       ^
+0

確かに - 私はそれがボンネットの下で起こっていることは間違いありません。しかし、関数の型を推定するのではなく、関数の型を指定したいのであれば、それは何ですか?確かに、私がその型を書くことができないものを作ることはできないでしょうか?それをできる?! –

+0

私はあなたがそれを行うことができるか分からない。すなわち、実際には、by-name引数に対応する 'type'が存在します。例えば。 'gg.getClass.getMethods.find(_。getName ==" apply ")。get'は、引数型の' Function0'を返します。しかし*コンパイラ*の場合、この変換はまだ行われていないので、 'Function0'が必要な型ではないことを伝えます(あなたの前回の試行前)。 –

関連する問題