私はちょうどコンピュータプログラムの構造と解釈のアイデアに出くわしました:
データは単なるダムコードであり、コードは単なるスマートデータです
私はそれが何を意味するのか理解できません。誰かが私がそれをよりよく理解するのを手伝ってくれる?
私はちょうどコンピュータプログラムの構造と解釈のアイデアに出くわしました:
データは単なるダムコードであり、コードは単なるスマートデータです
私はそれが何を意味するのか理解できません。誰かが私がそれをよりよく理解するのを手伝ってくれる?
これは、SICP の基本的な教訓の 1 つであり、コンピューター サイエンスの最も強力なアイデアの 1 つです。それはこのように動作します:
私たちが「コード」と考えているものは、実際にはそれ自体で何かを行う力を持っていません。コードは、解釈のコンテキスト内でのみプログラムを定義します。そのコンテキストの外では、プログラムは単なる文字列です。コードの意味は、コードを実行するシステムによって定義されます。このシステムは、コードをデータとして扱います。それはあなたがやりたかったことです。C ソース コードは、C コンパイラによって、作成するオブジェクト ファイルを記述するデータとして解釈されます。オブジェクト ファイルは、実行のためにキューに入れたいマシン命令を記述したデータとしてローダーによって扱われます。
解釈された言語には、多くの場合、データをコードとして扱うメカニズムが含まれています。つまり、何らかの形式でコードを関数に渡してから実行できます。実行時にコードを生成することもできます。
#!/usr/bin/perl
# Note that the above line explicitly defines the interpretive context for the
# rest of this file. Without the context of a Perl interpreter, this script
# doesn't do anything.
sub foo {
my ($expression) = @_;
# $expression is just a string that happens to be valid Perl
print "$expression = " . eval("$expression") . "\n";
}
foo("1 + 1 + 2 + 3 + 5 + 8"); # sum of first six Fibonacci numbers
foo(join(' + ', map { $_ * $_ } (1..10))); # sum of first ten squares
スキームなどの一部の言語には、「ファーストクラス関数」の概念があります。これは、関数をデータとして扱い、本当に必要になるまで評価せずに渡すことができることを意味します。
要するに、「コード」と「データ」の間の分割はほとんど恣意的であり、パースペクティブのみの機能です。抽象化のレベルが低いほど、コードは「よりスマート」である必要があります。コードには、実行方法に関するより多くの情報が含まれている必要があります。一方、インタプリタが提供する情報が多ければ多いほど、コードはますます馬鹿げたものになり、まったく賢くないデータのように見え始めます。
コードを記述する最も強力な方法の 1 つは、必要なものを簡単に説明することです。データは、解釈コンテキストによって必要なものを取得する方法を説明するコードに変換されます。これを「宣言型プログラミング」と呼びます。
具体的な例として、HTML を考えてみましょう。HTML は、チューリング完全なプログラミング言語を記述していません。単なる構造化データです。その構造には、解釈コンテキストの動作を制御できるいくつかのスマートが含まれていますが、多くのスマートは含まれていません。一方で、平均的な Web ページに表示されるテキストの段落よりも多くのスマート情報が含まれています。これらはかなりばかげたデータです。
セキュリティのコンテキストでは、バッファオーバーフローが原因で、データとして考えていたもの(イメージなど)がコードとして実行され、マシンが起動する可能性があります。
ソフトウェア開発のコンテキスト:多くの開発者は、「ハードコーディング」することを非常に恐れており、構成ファイルに変更しなければならない可能性のあるパラメーターを抽出することに非常に熱心です。これは多くの場合、構成ファイルは単なる「データ」であり、コード内の何かを変更する場合のような問題(コンパイル、デプロイメント、テスト)を発生させることなく、簡単に変更できる(顧客によるperhapy)という考えに基づいています。
これらの開発者が気付いていないのは、この「データ」がプログラムの動作に影響を与えるため、実際にはコードであるということです。プログラムが破損する可能性があり、そのような変更後に完全なテストを必要としない唯一の理由は、正しく実行された場合、構成可能な値が非常に具体的で十分に文書化された効果を持ち、無効な値または壊れたファイル構造がプログラム。
ただし、非常に頻繁に発生するのは、構成ファイルの構造がそれ自体でプログラミング言語になり、制御フローとすべてが完備されていることです。アプリケーションを完全に壊すことなく触れることができます。
したがって、Schemeのような言語では、コードでさえファーストクラスのデータとして扱われます。関数とラムダ式は、他のコードと同じように扱うことができます。たとえば、他の関数とラムダ式に渡すことができます。これはすべて非常に明確になるので、テキストを続けることをお勧めします。
これは、コンパイラでの記述から理解する必要があるものです。
コンパイラの一般的な手順の 1 つは、プログラムを抽象構文ツリーに変換することです。表現は多くの場合、[+, 2, 3] のようなツリーのようになります。ここで、+ はルートであり、2, 3 は子です。
Lisp 言語は、これを単にデータとして扱います。したがって、AST ツリーのように見えるリストであるデータとコードの間に分離はありません。
コードは間違いなくデータですが、データが常にコードであるとは限りません。基本的な例である顧客名を見てみましょう。これはコードとは関係ありません。アプリケーションの技術的(偶発的な) 側面とは対照的に、機能的な (不可欠な) ものです。
技術的/偶発的なデータはコードであり、機能的/重要なデータはそうではないと言えるでしょう。