誰かが良い例でそれを明確に説明できますか?関数型プログラミングについて説明しているときに、Scalaでこのステートメントに出くわしました。
6 に答える
「ファーストクラス」であることは、正式に定義された概念ではありませんが、一般的に、エンティティには次の 3 つのプロパティがあることを意味します。
これは、「通常の」値を使用できる場所ならどこでも制限なく使用できます。つまり、関数から受け渡したり、コンテナに入れたりすることができます。
これは、「通常の」値が可能な場所ならどこでも、つまりローカルに、式などで、無制限に構築できます。
「通常の」値と同様の方法で型付けできます。つまり、そのようなエンティティに割り当てられた型があり、他の型と自由に組み合わせることができます。
関数の場合、(2) は特に、ローカル関数がスコープ内のすべての名前を使用できることを意味します。つまり、レキシカル クロージャがあります。多くの場合、構築用の無名形式 (無名関数など) が付属していますが、これは厳密には必要ありません (たとえば、言語に十分な一般的な let 式がある場合)。ポイント (3) は、型指定されていない言語では自明に当てはまります。
これで、Scala (および関数型言語) の関数がファーストクラスと呼ばれる理由がわかります。その他の例を次に示します。
C/C++ の関数は一流ではありません。(1) と (3) はおそらく関数ポインターを介して使用できますが、(2) は適切な関数ではサポートされていません。(見落としがちなポイントです。)
同様に、配列と構造体は C の世界では一流ではありません。
Scala のクラスはファーストクラスではありません。それらを定義してネストすることはできますが、たとえば関数に渡すことはできません (そのインスタンスのみ)。ファーストクラスのクラスを持つ OO 言語があり、実際、Scala の設計に情報を提供したいわゆる nuObj 計算もそれを可能にします。
ファーストクラスのモジュールは、ML に似た言語でしばしば望まれる機能です。それらは決定不能な型チェックにつながるため、困難です。一部の ML ダイアレクトでは、モジュールをファーストクラスの値としてラップすることができますが、これはモジュール自体をファーストクラスにするものではありません。
これは、整数やシーケンスなどと同じ方法で関数を渡すことができることを意味します。
例(Scalaではありませんが):
>>> def add2(x):
... return x + 2
...
>>> map(add2, [1, 2, 3])
[3, 4, 5]
どのプログラミング言語にも、プログラムを作成するために値を操作するために使用できる言語機能の基本セットがあります。これらは、「値を関数に渡す」、「変数を値にバインドし、変数を値であるかのように使用する」などです。
ある言語が「第一級の値としての X」を持っている、または「第一級の X」を持っているという主張が見られるときはいつでも、これは、その言語が X でそれらの基本的な言語機能を使用できることを意味します。別の言い方をすれば、言語は X を値として扱うということです。
したがって、空白を埋めて、特定の種類のものを値として使用する言語がサポートされていることを示すことができます。たとえば、Scala にはファースト クラスの関数があります (または関数は Scala の値です)。
def plusOne(x : Int) = x + 1
val func : Int => Int = plusOne
println(func(1)) // prints 2
Python にはファーストクラスの関数がありますが、ファーストクラスのクラスもあります (Python ではクラスは値です)。
class Foo(object):
def __init__(self, thing):
self.thing = thing
cls = Foo
instance = cls(5)
print instance.thing # prints 5
print isinstance(thing, cls) # prints True
print isinstance(thing, Foo) # prints True
これは大したことではないように思えるかもしれませんが、値を使用して何ができるかを示すプログラミング言語の基本的な機能は、より多くのものにつながります。関数を値として使用できる場合は、(他の値と同様に) それらをコンテナーに入れたり、他のコードを呼び出して未知のものを取得したりできます。
対照的に、Java にはファーストクラスの関数がありません。関数を変数に入れたり、関数を別の関数に渡したり、関数の戻り値として受け取ったりすることはできません。関数は Java の値ではありません。Java にもファーストクラスのクラスはありません。
これは、関数がオブジェクトであることを意味します。また、他のオブジェクトと同じように、変数に割り当てたり、関数に渡したり、オブジェクトが実行できるその他のことを行うことができます。
たとえばf
、整数に1を加算する関数オブジェクトを保持する変数は次のとおりです。
scala> val f = (n: Int) => n + 1
f: Int => Int = <function1> // Has type Int => Int; Int input, Int output
:のmap
関数への引数として渡すことができます。List[Int]
scala> List(1,2,3).map(f) // map requires argument of type Int => Int
res0: List[Int] = List(2, 3, 4)
これは、Haskell や Erlang など、関数が第一級市民である純粋関数型言語から取られた用語です。これは、関数を引数として他の関数に渡すことができ、関数が他の関数を返すことができることを意味します。
関数は第一級市民であるため、矢印で示される関数型があります。haskel の場合: (->) skala の場合: (=>)
マップ機能を検討してください。これは、関数とリストを引数として取り、指定された関数をリストのすべての要素に適用する関数です。
ハスケルで:
map(\x->x+1)[1,2,3]
= [2,3,4]
スカラで:
List(1,2,3) map (x => x + 1)
= [2,3,4]
(\x->x+1)
および(x => x + 1)
は、map 関数に引数として渡される関数 (ラムダ式で示される) です。