RubyでいうElixir的な立ち位置?Pythonにコンパイルされる関数型言語、Coconut
今朝、Quoraでたまたま見つけました、Coconutという言語
Coconutは、Pythonにコンパイルされる関数型プログラミング言語であり、Pythonの既存のライブラリも呼べるようです。詳しい説明は公式を参照するのが良いと思うので下に貼ります。
(たしかに、ちょっと立ち位置は違うかもしれませんが、RubyでいうElixir的な存在かもしれませんね)
Coconut - Simple, elegant, Pythonic functional programming.
Coconut - github
Coconutセットアップ
Coconut
を動かすには Python
が必要です。
(ちなみにちょっと試したいだけならPCにインストールすることなく、こちらのオンラインエディターで試せます)
セットアップはPython
が入っている環境で、ターミナルを立ち上げ、下記のコマンドを実行するだけ。
(Coconutの公式を覗くと、特にPythonのバージョンは選ばないとのことです)
pip install coconut
Coconutのインタプリタを立ち上げて、Pythonを書いてみる
早速Coconut Tutorialを参照しながら Coconut
を動かしてみます。
Coconutのインタプリタを起動させるにはターミナル上で下記のコマンドを叩きます。
coconut
すると、下記のようになり、coconutに触れます。
Coconut Interpreter:
(type 'exit()' or press Ctrl-D to end)
>>>
終了する場合は Ctrl + D
もしくはインタプリタ上で exit()
と打ってください。
Coconut
ではPython
も扱えます。例えば
>>> print("Hello World")
Hello World
>>> 1 + 1
2
Python
のチュートアリルにあるような下記のような式も書くことができます。
>>> x = int(input("Please enter an integer: "))
Please enter an integer: 42
>>> if x < 0:
x = 0
print('Negative changed to zero')
elif x == 0:
print('Zero')
elif x == 1:
print('Single')
else:
print('More')
More
for
文も可能です。
>>> words = ['cat', 'window', 'defenestrate']
>>> words
['cat', 'window', 'defenestrate']
>>> for w in words:
print(w)
cat
window
defenestrate
Coconutのインタプリタを立ち上げて、Coconutを書いてみる
ここからはCoconut
ならではの書き方で書いてみようと思います。
(といっても、大半はcoconut tutorial参考にしているだけですが)
pipeline-style programming(パイプ演算子)
>>> "hello, world!" |> print
hello, world!
prettier lambdas(lambda式)
>>> x -> x ** 2
<function <lambda> at 0x1034f48c8>
partial application(部分適用)
>>> range(10) |> map$(pow$(?, 2)) |> list
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
pattern-matching(パターンマッチング)
>>> match [head] + tail in [0, 1, 2, 3]:
print(head, tail)
0 [1, 2, 3]
Destructuring assignment(分割代入)
>>> {"list": [0] + rest} = {"list": [0, 1, 2, 3]}
>>> rest
[1, 2, 3]
>>> print({"list": [0] + rest})
{'list': [0, 1, 2, 3]}
infix notation(中置記法)
>>> def add(x,y):
return x + y
>>> add
<function add at 0x104811bf8>
>>> 5 `add` 3 * 6
23
operator functions
>>> product = reduce$(*)
>>> product
functools.partial(<built-in function reduce>, <built-in function mul>)
>>> def add(a,b):
return a+b
>>> add
<function add at 0x1102992f0>
>>> product2 = reduce$(add)
>>> product2
functools.partial(<built-in function reduce>, <function add at 0x1102992f0>)
function composition
>>> def plus1(x) = x + 1
>>> def square(x) = x * x
>>> (plus1..square)(3) == 10
True
lazy lists
>>> (| print("hello,"), print("world!") |) |> consume
hello,
world!
deque([], maxlen=0)
parallel programming
>>> range(100) |> parallel_map$(pow$(2)) |> list
[1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536, 131072, 262144, 524288, 1048576, 2097152, 4194304, 8388608, 16777216, 33554432, 67108864, 134217728, 268435456, 536870912, 1073741824, 2147483648, 4294967296, 8589934592, 17179869184, 34359738368, 68719476736, 137438953472, 274877906944, 549755813888, 1099511627776, 2199023255552, 4398046511104, 8796093022208, 17592186044416, 35184372088832, 70368744177664, 140737488355328, 281474976710656, 562949953421312, 1125899906842624, 2251799813685248, 4503599627370496, 9007199254740992, 18014398509481984, 36028797018963968, 72057594037927936, 144115188075855872, 288230376151711744, 576460752303423488, 1152921504606846976, 2305843009213693952, 4611686018427387904, 9223372036854775808, 18446744073709551616, 36893488147419103232, 73786976294838206464, 147573952589676412928, 295147905179352825856, 590295810358705651712, 1180591620717411303424, 2361183241434822606848, 4722366482869645213696, 9444732965739290427392, 18889465931478580854784, 37778931862957161709568, 75557863725914323419136, 151115727451828646838272, 302231454903657293676544, 604462909807314587353088, 1208925819614629174706176, 2417851639229258349412352, 4835703278458516698824704, 9671406556917033397649408, 19342813113834066795298816, 38685626227668133590597632, 77371252455336267181195264, 154742504910672534362390528, 309485009821345068724781056, 618970019642690137449562112, 1237940039285380274899124224, 2475880078570760549798248448, 4951760157141521099596496896, 9903520314283042199192993792, 19807040628566084398385987584, 39614081257132168796771975168, 79228162514264337593543950336, 158456325028528675187087900672, 316912650057057350374175801344, 633825300114114700748351602688]
tail call optimization(末尾再帰)
>>> def factorial(n, acc=1):
case n:
match 0:
return acc
match _ is int if n > 0:
return factorial(n-1, acc*n)
>>> factorial
<function factorial at 0x10fdb49d8>
>>> factorial(10)
3628800
algebraic data types(代数的データ型)
>> data Empty()
data Leaf(n)
data Node(l, r)
>>> Empty
<class '__main__.Empty'>
>>> Leaf
<class '__main__.Leaf'>
>>> Node
<class '__main__.Node'>
>>> def size(Empty()) = 0
>>> addpattern def size(Leaf(n)) = 1
>>> addpattern def size(Node(l, r)) = size(l) + size(r)
>>> size
addpattern(<function size at 0x1108022f0>)(*[<function size at 0x1109687b8>, <function size at 0x110a72378>])
coconut.vimを使ってVimにシンタックスハイライトを設定する
coconuts.vim - githubというものが既にあるので、そちらを使用します。
私は現在プラグイン管理に dein
を使用しているので、plugins.toml
に下記のように記述します
[[plugins]]
repo = 'manicmaniac/coconut.vim'
vim-plug
を使っている場合は、下記の一行を~/.vimrc
に追加する形になるでしょうか?
(動作未確認なので、間違えていたらすみません)
Plug 'manicmaniac/coconut.vim'
language-coconutを用いてAtomにcoconutのシンタックスハイライトを設定する
Atomのシンタックスハイライト設定には下記のプラグインを使うようです。
Atom
を開いて Preference
から Install
で検索窓に language-coconut
を入れれば、パッケージは見つかると思います。
Coconutファイルを作成してプログラムを実行する
シンタックスハイライトの設定が完了したら、Coconut
のファイルを作成してみます。
Coconut
のファイル拡張は .coco
だそうです。なんだか、可愛いですね。
hello_world.coco
というファイルを作成してみます。
vim hello_world.coco
Python
とは異なり、ファイルのヘッダーは下記のようになるようですが、これらはCoconut
コンパイラー側で自動的に追加されるようなので、実際は不要のようです。
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
from __future__ import print_function, absolute_import, unicode_literals, division
簡単なサンプルをファイルに書いてCoconut
を実行してみます。
"hello, world!" |> print
コンパイラーを使ってCoconutファイルをコンパイルする
coconut
コマンドを使って、hello_world.coco
をコンパイルする
coconut hello_world.coco
実行結果は下記の通り
$coconut hello_world.coco
Compiling hello_world.coco ...
Compiled to hello_world.py .
カレントにhello_world.py
が生成されました。
このhello_world.py
を開いてみると、コンパイルされたCoconut
コードが確認できます。
ここに貼ろうと思ったのですが結構大量だったのでやめました。ご自身で確認してみてください。
python
コマンドで実行すると、下記のような結果になります。
$python hello_world.py
hello, world!
今日はここまで。続きはまた後日、少しずつ書き進めていきます。
※関数型言語は不慣れなため、もし間違った解釈している所があれば教えていただけますと幸いです。