Admittedly something small.

ちょっと小さいのはたしかですが。

【短編ポエム】Haskell/PureScriptの関数呼び出しはRuby/Python/JavaScriptよりイケている

2016年9月22日 ( 8年前に投稿 )

Ruby Python JavaScript Haskell ポエム

* [「Rubyのここがイケてない」を論破したい](http://qiita.com/ocadaruma/items/4c66422cb7761f99e0fe)

> Proc#callがださい

たとえば、ふたつの引数の和を出力する関数`add`や`sum`について考えてみます。PythonやJavaScriptなら次のようなコードを書くことができます。

```py:python
def add(x, y):
    print(x + y)
 
sum = add    # そのまま代入できる
 
add(1, 2) 
sum(1, 2)    # addとsumの呼び出し方に違いはない
```

```js:JavaScript
function add(x, y){
    console.log(x + y);
}

sum = add    // そのまま代入できる

add(1, 2) 
sum(1, 2)    // addとsumの呼び出し方に違いはない
```

しかし、Rubyではメソッドをそのまま他の変数に代入したりはできず、`proc`や`lambda`で`Proc`オブジェクトを作ってから渡さなければなりませんし、受け取った側も`call`をつかって呼ぶ必要があります。これは`apply`メソッドを呼ばなければならないJavaあたりでも同じですね。

```ruby:Ruby
def add(x, y)
    puts (x + y)
end

sum = proc{|x, y| add(x, y)}  # procやlambdaで包む必要がある

add 1, 2          
sum.call 1, 2                 #callで呼び出す必要があり、addとsumの使い方が異なってしまう  
```

なるほどこれはダサい。でもこれにはRuby側の反論もあって、Rubyでは引数がないときはメソッド呼び出しで括弧を省略できるという利点もあります。

```js:JavaScript
function answer(){
    console.log(42)
}

answer()        // 括弧がいる
```

```ruby:Ruby
def answer
    puts 42
end

answer            # 括弧がいらない
```

> 私もちょっとダサい、っつーか扱い辛いと感じることがあります。が、これは文中にも書いてある通り、Rubyに価値を与えている独特なスタイルとのトレードオフでしょう。

JavaScriptやPythonにこのような括弧の省略を導入しようとしても、関数オブジェクトそのものを表す構文と衝突してしまうので不可能です。そんなわけで、これを見る限り必ずしもどちらがいいと言い切れないようにみえるのですが……。




# Haskell/PureScriptでは

Haskell/PureScriptでは、このジレンマが解決します。

```haskell:PureScript
add x y = logShow (x + y)    -- addには引数があります

sum = add                    -- 関数は第一級なので、普通に代入できます

answer = logShow 42          -- answerには引数がありません

fortyTwo = answer           -- answerの値も第一級なので、そのまま別の変数に代入することもできます

main = do
    add 1 2                  -- 3が出力されます。引数がある場合はもちろん普通に呼び出せます
    sum 1 2                  -- 3が出力されます。addとsumに呼び出しかたの違いはありません
    answer                   -- 42が出力されます。引数がない場合も、もちろん括弧はありません
    fortyTwo                 -- 42が出力されます。fortyTwoとanswerは同じものを指しているからです
```


Rubyの『引数のない関数呼び出しで括弧を省略できる』という利点と、Python/JavaScriptの『通常の関数呼び出しと、関数オブジェクトの呼び出しを区別しない』という利点の、ふたつの利点が両立しています。ふしぎ!Haskell/PureScriptでは何故こんなことができるのか、上のコードの各部はどういう意味なのか、どんな順序で実行が進んでいくのか、自分で考えてみると面白いかもしれません(脚注1)。


それに、上のPureScriptのコードを良く見ると、ピリオドもなければコロンもないし、カンマのひとつすら存在しません。予約語はコードブロックの始まりを告げる`do`のみ。Pythonのようにインデントでブロックが表現されているなど、異様なまでにコードの見た目がスッキリしているのがわかると思います。これもHaskell/PureScriptのコードの特徴です。極限まで構文上のノイズが絞られていて筆者はすごく読みやすいと思うのですが、何故か読みにくいと言われることもあります。

> これは文法の問題なので、もしかしたらこれらを両立させる文法をもった言語が将来開発されるかもしれません。

15年以上前からあります。使っている人が少なすぎて、あまり知られていませんが……。

引数がないときの括弧を省こうとするなど、Rubyを使う人はそういう構文上のオーバーヘッドを嫌う人が多いのかもしれません。Haskell/PureScriptはとにかく構文が簡潔ですから、Rubyが好きな人にも向いているんじゃないかと。このような細かいところは正直どうでもいいと私は思うのですが、私は普段『同期的な作用と非同期な作用をモナドで抽象化すると一貫性が生まれて便利だよ』みたいな重大なポイントについて利点の説明をしては『意味わかんねーよ文章長えよカス!』という感じで罵られているので、今回は『関数の引数の有無や第一級かどうかについて便利さと単純さが両立するよ』という、わかりやすいポイントについてなるべく簡潔に説明をしました。

----

----


脚注1  もっとも、Haskell/PureScriptを知らない人は絶対にわからないと思いますが。なお、これはPureScriptのコードなので、実行の順序がぐちゃぐちゃになるHaskell特有の変態仕様『遅延評価』は関係がありません

(この記事は同じ筆者が Qiita に投稿した記事の複製です。オリジナル記事)