命令型コードを純粋関数型に変換するプログラムを作成する必要があります。I / Oについては心配していません-そのためのいくつかの解決策を考えています-しかし、ローカル変数だけでなくヒープオブジェクトも処理する必要があります。
関数の呼び出しと戻りのたびにオブジェクトを渡し、TheWorld
そこから最適化して、使用されていない関数からそのパラメーターを削除しようとすることで、これを実行できると思います。しかし、それを行うためのより良い方法は知られていますか?
命令型コードを純粋関数型に変換するプログラムを作成する必要があります。I / Oについては心配していません-そのためのいくつかの解決策を考えています-しかし、ローカル変数だけでなくヒープオブジェクトも処理する必要があります。
関数の呼び出しと戻りのたびにオブジェクトを渡し、TheWorld
そこから最適化して、使用されていない関数からそのパラメーターを削除しようとすることで、これを実行できると思います。しかし、それを行うためのより良い方法は知られていますか?
このような翻訳を効率的に行うには、いくつかの方法があります。まず、結果としてCPS変換を使用してSSA変換を実行する価値があります。このようにして、変数と分岐を含む命令型コードから、相互に再帰的な些細な関数を取得します。暗黙的なスタックセマンティクスに依存する代わりに継続パラメーターを渡すことにより、関数呼び出し(および仮想呼び出しでさえ)を簡単にCPSすることもできます。
配列は変数と同じ方法で処理できます。SSA変換の前に、すべての配列アクセスをget
関数update
呼び出しに置き換える必要があります。関数呼び出しには、暗黙のコピーセマンティクスが必要です(ただし、この場合はエイリアシングに注意してください)。構造についても同じです。
また、コピーのセマンティクスを維持できない場合にのみTheWorld
、割り当てられたすべてのオブジェクトを保持し、オブジェクトの1つを変更するたびに完全にコピーする必要があるこのオブジェクトが必要です。
SK-logicが指摘しているように、SSA形式で命令型プログラムを表すことができます。
ただし、CPS変換を適用するのではなく、命令型SSA表現を、Zadarnowski et alによって公開されたアルゴリズムに基づいて、制限付き関数型言語である「AdministrativeNormalForm」の同等の純粋な関数型プログラムに直接変換できます。
2つの言語は次のように与えられます。
SSA形式のプログラムをANFに自動的に変換するためのアルゴリズムを提供する「SSA最適化アルゴリズムの機能的展望」を参照してください。
多くの関数型プログラミング言語では、一連のローカル変数の割り当てを一連のlet
式に置き換えることができます。
たとえば、このC関数は次のように変換できます。
int example(int a,int b){
a += 1;
b += 2;
if(a == 1){
b += 1;
}
else if(b == 1){
a += 1;
}
return a + b;
}
Futharkプログラミング言語の同等の関数は、レコードデータ構造を使用してローカル変数を格納し、次のように記述できます。
let example a b =
let vars = {a,b} in
let vars = vars with a = vars.a + 1 in
let vars = vars with b = vars.b + 2 in
let vars = (if vars.a == 1 then
let vars = vars with b = vars.b + 1 in
vars
else if b == 1 then
let vars = vars with a = vars.a + 1 in
vars
else
vars)
in vars.a + vars.b
場合によっては、一連の命令文を単一の算術式に変換することも可能です。Prologでは、これはサブタームを置き換えることによって行うことができます:
:- use_module(prolog_vars_list).
:- set_prolog_flag(double_quotes, chars).
:- initialization(main).
main :-
To_solve = (Z=11,
Z=Z*2,
A=1+A,
A=A+2,
A = Z+1,
A = A * 2,
A=A+3+Z+P),
run_imperative(To_solve,B),
%print the input
writeln(To_solve),
%now print the output
writeln(B).
run_imperative(A,B) :- imperative_to_declarative(A,_=B).
imperative_to_declarative((A,B,C),D1) :-
imperative_to_declarative((B,C),D),imperative_to_declarative((A,D),D1).
imperative_to_declarative((A=A1,B=B1),(_=C)) :-
replace(A,A1,B1,C).
replace(Subterm0, Subterm, Term0, Term) :-
( Term0 == Subterm0 -> Term = Subterm
; var(Term0) -> Term = Term0
; Term0 =.. [F|Args0],
maplist(replace(Subterm0,Subterm), Args0, Args),
Term =.. [F|Args]
).
モナドまたは再帰を使用してwhileループを実装する方法もいくつかあります。