はじめに
Elixirを始めた頃、関数型って何んだろう、きっと関数単位がタスクになるんだ、と思いました。というのも、今まで、いろんな制限によりタスク単位が大きくなっていて分割できなかったんです。
学んでいく内に関数型の意味がわかってきて、どうも違うんだとわかり、はて、今まで携わってきた組込みシステムを置き換えができるのだろうか、と疑問になりました。
ここでは、適さないかもと思う点を書いてみます。
functionの言葉には二つの意味がある
プログラミングから見るとfunctionを関数とは呼んではいるものの、実際にはその中身は機能ではないか。元々、functionは機能の意味から数値を変換・作用するものとして、関数と呼び出したのではないだろうか。
つまり、functionには数学的な関数と機能との二つの意味になっている。そして、functional programmingは「関数型」数学的な特徴がある事を指している。
関数とは(google検索から)
ある値(入力)を入れると、決まった規則に従って別の値(出力)がただ一つ決まる仕組みや対応関係のこと。
数学 : 「xの値が決まるとyの値が一つに決まる関係」を指し、y = f(x)のようなもの
プログラミング : 「データを受け取り処理して結果を返す命令のまとまり」として、コードの再利用性を高めるために使われる。
関数型プログラミングについて
数学的な関数で、入力する値からひとつの結果しか、戻らない(純粋関数)のが基本となっています。変数の定義はない、持てない。変数により、結果が変わる事がないようになっています。
プログラムとしては関数内で結果が変わる処理が一番の不具合、悪さをする原因なので、それを防ぐためにこの言語があると言っても良いのでは、と思います。
ちなみにパイプ処理があるのは、結果が定まっている関数型だからこそ、利用できるのではないでしょうか。とパイプの話がでる度に思います。ある処理からの出力がその都度変化した場合(例えば、:error)、パイプで受け取る処理は混乱するに違いありません。
機能は埋め込めないのでは
関数型は数学的な関数で結果を求めるもの、組込み(機能)は結果よりもどう処理するかを決めるもの。とは言え、機能にも結果を求める機能がありますが、関数型は処理はどうであれ、結果さえ正しければ良いのだと思います。
また、関数型には変数定義できないとの問題があり、機能を作る上で障害だと思います。
オブジェクト指向を考えてみると、オブジェクトはデータ(状態)とメソッド(処理)との構成で機能を実現されています。オブジェクト指向に限らず、あらゆるプログラムはこのデータと処理で成り立っていると考えます。その点から言えば、どう処理するかを関数型に埋め込むのは困難であると思います。
実際のコードから機能を説明してみます。いやはや、説明できるか否かはあまり自信がありませんが。
def flicker(cb) do
IO.puts("#{cb.func} (#{timestamp(cb)})")
Timer.set_timcb(:cyclic, cb.mod, div(250, FSM.get_tick), :tim)
flicker_loop(cb)
end
def flicker_loop(cb) do
{eve, _msg} = FSM.rcv_msg()
case eve do
:flk_off ->
Timer.set_timcb(:cancel, cb.mod, 0, :tim)
%{cb | func: :ledoff, arg: 0}
:tim ->
cb =
if cb.arg == 0 do
IO.puts("flk led off (#{timestamp(cb)})")
%{cb | arg: 1}
else
IO.puts("flk led on (#{timestamp(cb)})")
%{cb | arg: 0}
end
flicker_loop(cb)
_ ->
IO.puts("#{cb.func} cont(#{timestamp(cb)})")
flicker_loop(cb)
end
end
関数はflicker処理で、タイマーイベントによりflickerさせるとの処理にしています。
戻り値cbは、Elixir上、変数が持てないので戻り値としているだけ、本来、戻り値(結果)には意味はありません。つまり、この関数はフリッカーさせるという機能であり、結果を得るとの処理ではなく機能そのもので、関数型から逸脱していると思います。
また、flicker_loop()で:flk_offのイベントが来ない限り、タイマーにより永久に動くようにしています。(エンドレスループ) このループの処理をするには再帰呼び出しを使い、while(1)のような処理はありません。case文、if文を含め、全てのマクロは関数となっており、値が戻ってくる事が前提となり、while(1)のような戻ってこない関数は定義できないのではないでしょうか。
関数型で機能を実現する事はなんとか可能でしょうが、それって、もはや関数型プログラミングと呼べなくなるのでは、と思います。
まとめ
いろいろと分かりづらい事を書きましたが、自分でもわからない事だらけです。
機能を埋め込むにはどうしても何かの判断処理が必要となりますが、関数型ではその判断処理は入れないのが基本、と反しています。それでも、組込みで自分の思った通りに使えないか、やっている事は元は思想を壊す事になるなぁ、などと悩み続けています。