Coconutことはじめ

## RubyでいうElixir的な立ち位置？Pythonにコンパイルされる関数型言語、Coconut

今朝、Quoraでたまたま見つけました、Coconutという言語

[Quora - Pythonは悪い言語ではないと思うのですが、関数型プログラミングを試みようとすると苦痛が大きいです。関数型Pythonのようなものは存在しますか (Rubyに対するElixirのような) ？](https://qr.ae/TWKveY)


Coconutは、Pythonにコンパイルされる関数型プログラミング言語であり、Pythonの既存のライブラリも呼べるようです。詳しい説明は公式を参照するのが良いと思うので下に貼ります。
(たしかに、ちょっと立ち位置は違うかもしれませんが、RubyでいうElixir的な存在かもしれませんね)

[Coconut - Simple, elegant, Pythonic functional programming.](http://coconut-lang.org/)
[Coconut - github](https://github.com/evhub/coconut)


## Coconutセットアップ

`Coconut` を動かすには `Python` が必要です。
(ちなみにちょっと試したいだけならPCにインストールすることなく、こちらの[オンラインエディター](https://cs121-team-panda.github.io/coconut-interpreter/)で試せます)

セットアップは`Python`が入っている環境で、ターミナルを立ち上げ、下記のコマンドを実行するだけ。
(Coconutの公式を覗くと、特にPythonのバージョンは選ばないとのことです)

```bash
pip install coconut
```

## Coconutのインタプリタを立ち上げて、Pythonを書いてみる

早速[Coconut Tutorial](https://coconut.readthedocs.io/en/master/HELP.html)を参照しながら `Coconut` を動かしてみます。

Coconutのインタプリタを起動させるにはターミナル上で下記のコマンドを叩きます。

```bash
coconut
```

すると、下記のようになり、coconutに触れます。

```bash
Coconut Interpreter:
(type 'exit()' or press Ctrl-D to end)
>>>
```

終了する場合は `Ctrl + D` もしくはインタプリタ上で `exit()` と打ってください。

`Coconut`では`Python`も扱えます。例えば

```python
>>> print("Hello World")
Hello World
```

```
>>> 1 + 1
2
```

`Python` のチュートアリルにあるような下記のような式も書くことができます。

```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`文も可能です。

```python
>>> 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(パイプ演算子)

```python
>>> "hello, world!" |> print
hello, world!
```

prettier lambdas(lambda式)

```python
>>> x -> x ** 2
<function <lambda> at 0x1034f48c8>
```

partial application(部分適用)

```python
>>> range(10) |> map$(pow$(?, 2)) |> list
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
```

pattern-matching(パターンマッチング)

```python
>>> match [head] + tail in [0, 1, 2, 3]:
    print(head, tail)
0 [1, 2, 3]
```

Destructuring assignment(分割代入)

```python
>>> {"list": [0] + rest} = {"list": [0, 1, 2, 3]}

>>> rest
[1, 2, 3]

>>> print({"list": [0] + rest})
{'list': [0, 1, 2, 3]}
```

infix notation(中置記法）

```python
>>> def add(x,y):
      return x + y

>>> add
<function add at 0x104811bf8>

>>> 5 `add` 3 * 6
23
```

operator functions

```python
>>> 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

```python
>>> def plus1(x) = x + 1

>>> def square(x) = x * x

>>> (plus1..square)(3) == 10
True
```

lazy lists

```python
>>> (| print("hello,"), print("world!") |) |> consume
hello,
world!
deque([], maxlen=0)
```


parallel programming

```python
>>> 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(末尾再帰)

```python
>>> 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(代数的データ型)

```python
>> 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](https://github.com/manicmaniac/coconut.vim)というものが既にあるので、そちらを使用します。

私は現在プラグイン管理に `dein`を使用しているので、`plugins.toml`に下記のように記述します

```toml
[[plugins]]
repo = 'manicmaniac/coconut.vim'
```

`vim-plug` を使っている場合は、下記の一行を`~/.vimrc`に追加する形になるでしょうか？
(動作未確認なので、間違えていたらすみません)

```vim
Plug 'manicmaniac/coconut.vim'
```

## language-coconutを用いてAtomにcoconutのシンタックスハイライトを設定する

Atomのシンタックスハイライト設定には下記のプラグインを使うようです。

[language-coconut - github](https://github.com/enilsen16/language-coconut)

`Atom` を開いて `Preference` から `Install`で検索窓に `language-coconut` を入れれば、パッケージは見つかると思います。


## Coconutファイルを作成してプログラムを実行する

シンタックスハイライトの設定が完了したら、`Coconut`のファイルを作成してみます。
`Coconut`のファイル拡張は `.coco`だそうです。なんだか、可愛いですね。

`hello_world.coco`というファイルを作成してみます。

```bash
vim hello_world.coco
```

`Python`とは異なり、ファイルのヘッダーは下記のようになるようですが、これらは`Coconut`コンパイラー側で自動的に追加されるようなので、実際は不要のようです。

```python
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
from __future__ import print_function, absolute_import, unicode_literals, division
```


簡単なサンプルをファイルに書いて`Coconut`を実行してみます。

```python
"hello, world!" |> print
```

### コンパイラーを使ってCoconutファイルをコンパイルする

`coconut`コマンドを使って、`hello_world.coco`をコンパイルする

```bash
coconut hello_world.coco
```


実行結果は下記の通り

```bash
$coconut hello_world.coco
Compiling         hello_world.coco ...
Compiled to       hello_world.py .
```

カレントに`hello_world.py`が生成されました。
この`hello_world.py`を開いてみると、コンパイルされた`Coconut`コードが確認できます。
ここに貼ろうと思ったのですが結構大量だったのでやめました。ご自身で確認してみてください。

`python`コマンドで実行すると、下記のような結果になります。

```bash
$python hello_world.py
hello, world!
```

---

今日はここまで。続きはまた後日、少しずつ書き進めていきます。

※関数型言語は不慣れなため、もし間違った解釈している所があれば教えていただけますと幸いです。