59

私がとても好きなことの 1 つは、さまざまなプログラミング言語について読むことです。現在、私は Scala を学んでいますが、Groovy、Clojure、Python などに興味がないわけではありません。これらすべての言語には、独自のルック アンド フィールといくつかの特徴的な機能があります。Clojure の場合、これらの設計上の決定の 1 つがわかりません。私の知る限り、Clojure はその関数型パラダイムを非常に重視しており、可能な限り不変の「変数」を使用するよう強制しています。では、値の半分が不変である場合、言語が動的に型付けされるのはなぜでしょうか?

Clojure の Web サイトには次のように書かれています。

何よりもまず、Clojure は動的です。つまり、Clojure プログラムは、コンパイルして実行するだけのものではなく、対話できるものです。

うーん、それは完全に奇妙に聞こえます。プログラムがコンパイルされると、それを変更することはできなくなります。「対話」できることは確かです。それが UI の目的ですが、Web サイトがきちんとした「動的」GUI を意味するわけではありません。

Clojure は動的型付けからどのように恩恵を受けるか

私が言っているのは Clojure の特殊なケースであり、動的型付けの一般的な利点ではありません。

動的型システムは関数型プログラミングの改善にどのように役立ちますか

繰り返しますが、「int a;」をこぼさないことの喜びを知っています。ソース コード全体に影響を与えますが、型推論によって多くの苦痛が軽減されます。したがって、動的型付けが関数型言語の概念をどのようにサポートしているかを知りたいだけです。

4

5 に答える 5

26

プログラムがコンパイルされると、それを変更することはできなくなります。

これは間違っています。Lisp (Clojure は Lisp の方言と見なすことができます) や Smalltalk などのイメージベースのシステムでは、コンパイルされた環境を変更できます。このような言語での開発とは、通常、実行中のシステムで作業し、関数定義、マクロ定義、パラメーターなどを追加および変更することを意味します (追加とは、コンパイルしてイメージにロードすることを意味します)。

これには多くの利点があります。1 つは、すべてのツールがプログラムと直接やり取りできるため、システムの動作を推測する必要がないことです。また、コンパイルされた各ユニットは非常に小さいため (すべてを再コンパイルすることは非常にまれです)、長いコンパイルの一時停止もありません。NASA JPL はかつて、何十万キロも離れた宇宙の探査機で実行中の Lisp システムを修正しました。

このようなシステムでは、実行時に型情報を利用できるようにすることは非常に自然なことです (これが動的型付けの意味です)。もちろん、コンパイル時に型推論と型チェックを行うことを妨げるものは何もありません。これらの概念は直交しています。Modern Lisp の実装は通常、両方を行うことができます。

于 2011-02-24T23:26:13.490 に答える
18

まず第一に、Clojure は Lisp であり、Lisp は伝統的に常に動的に型付けされてきました。

あなたが引用した抜粋として2番目に、Clojureは動的言語であると述べました。これは、とりわけ、実行時に新しい関数を定義したり、実行時に任意のコードを評価したりできることを意味します。これらのことはすべて、静的に型付けされた言語で行うのは困難または不可能です (至る所にキャストを塗りつぶす必要はありません)。

もう 1 つの理由は、マクロによって型エラーのデバッグが非常に複雑になる可能性があることです。マクロで生成されたコードによって生成された型エラーに対して意味のあるエラー メッセージを生成することは、コンパイラにとってかなりの作業になると思います。

于 2011-02-24T21:05:24.403 に答える
15

純粋に関数型の言語でも、対話型の read-eval-print-loop を持つことができ、型推論が容易になることに同意します。Clojure は「jvm のための Lisp」であることで Lisp プログラマーを惹きつけたいと考え、他の Lisp のように動的であることを選択したと思います。もう 1 つの要因は、型システムは言語の最初のステップとして設計する必要があり、言語の実装者がそのステップをスキップする方が速いということです。

于 2011-02-24T21:18:14.370 に答える
7

(誤解が多すぎるため、元の回答を言い換えています)

Clojure (および任意の Lisp) を動的に型付けしておく理由の 1 つは、マクロの作成を単純化することです。要するに、マクロは、非常に多くの異なるタイプ (通常はあらゆるオブジェクト) のノードを含むことができる抽象構文木 (AST) を扱います。理論的には、完全に静的に型付けされたマクロ システムを作成することは可能ですが、実際には、そのようなシステムは通常、制限され、まばらに広がっています。以下の例と、スレッド内の詳細な議論を参照してください。


EDIT 2020 : うわー、この回答を投稿してから9年が経過しましたが、人々はまだコメントを追加しています. 私たち全員が残した何という遺産でしょう!

一部の人々は、静的に型付けされた言語を使用しても、コードをデータ構造として表現することを妨げないことをコメントで指摘しました。そして、厳密に言えば、これは真実です。共用体型を使用すると、言語の構文を含め、あらゆる複雑なデータ構造を表現できます。ただし、構文を表現するには、表現力を減らすか、静的型付けのすべての利点を失うほど広い共用体を使用する必要があると私は主張します。この主張を証明するために、別の言語、ジュリアを使用します。

Julia はオプションで型指定されます。任意の関数または構造体フィールドを特定の型に制限することができ、Julia はそれをチェックします。Exprこの言語は、型と型を使用する第一級市民として AST をサポートしSymbolます。式の定義は次のようになります。

struct Expr
  head::Symbol
  args::Vector{Any}
end

式は、常にシンボルであるヘッドと、任意の型を持つ可能性のある引数のリストで構成されます。Julia はUnion、引数を特定の型 (たとえばSymbols やその他Exprの s ) に制限できる special もサポートしています。

struct Expr
  head::Symbol
  args::Vector{Union{Symbol, Expr}}
end

たとえば、次のように表現するのに十分:(x + y)です。

dump(:(x + y))
Expr
  head: Symbol call
  args: Array{Any}((3,))
    1: Symbol +
    2: Symbol x
    3: Symbol y

ただし、Julia は式で他の多くの型もサポートしています。明白で役立つ例の 1 つは、リテラルです。

:(x + 1)

さらに、補間を使用したり、手動で式を作成して、任意のオブジェクトを AST に配置したりできます。

obj = create_some_object()

ex1 = :(x + $objs)
ex2 = Expr(:+, :x, obj)

これらの例は単なる面白い実験ではなく、実際のコード、特にマクロで積極的に使用されています。したがって、式の引数を特定の型の結合に制約することはできません。式には任意の値が含まれる可能性があります。

もちろん、新しい言語を設計するときは、それに制限を加えることができます。おそらく、一部のコンテキストでは, and someExprのみを含むように制限すると便利です。しかし、これは Julia と Clojure の両方の単純さと柔軟性の原則に反しており、マクロの有用性を大幅に低下させます。SymbolExprLiteral

于 2011-02-24T21:03:43.930 に答える
4

それが世界/市場が必要としていたものだからです。すでに構築されているものを構築しても意味がありません。

JVMにはすでに静的に型付けされた言語があると聞きました;)

于 2011-02-25T00:52:59.420 に答える