目次

    Haskellとは?

    Haskellは1985年に開発されたプログラミング言語です。ちなみに名前は数学者、論理学者のHaskell Curryから取っているようです。Haskellは純粋関数型言語の1つ、つまり「副作用をなくす」=「元々の値を変えないこと」に特徴を持った言語です。

    どういうことかといえば、一度定義した変数などは上書きできないようにするというのが基本ということですね。JavaScriptで言うなら、for loopで配列に新しい値を加えていく(例えばlet arr=[]に何らかの値をpushすると、arrの値自体が変わります)のではなく、mapでもともとの値をコピー{arr.map(何らかの処理)とすると、その後どんな処理を加えても元々のarrの値は変わりません}して、コピーを変更していくような形を関数型言語では取ります。

    なんでこんな面倒なことをするのか?ということですが要は深刻なバグを減らすためです。
    JavaScriptに例えると、constの安全性の話に近いです。varやletを使うと値が置き換えられてしまうため、値を使おうとしたら誰かに変更されていて、全く別の値になっているということもあり得ます。

    100行以内のコードなら良いですが、1000行以上あるコードで変更箇所を見つけるのはかなりしんどい作業です...constは値が基本的に変更されないので、constで定義された変数は安心して使えます。
    関数型言語はconstのように一度定義した変数などを再代入、変更できないようにすることで深刻なバグを減らせ、安全性を担保できるようになっています。

    その他のHaskellの特徴としては

    ・遅延評価
    値が必要になった時に初めて値が読み込まれます。遅延ロードなどを使うときにHTMLなどでも使われる考え方ですね。なぜこれが大事なのかというと、必要ない処理をせずに済むことでパフォーマンスの向上につながります。

    ・型推論ができる
    HaskellはCやJavaなどと同じように型を必要とします。例えば const text = "おはよう" ではなく、const text: String = "おはよう"となります(この書き方はTypeScriptですが、わかりやすいので拝借...)。

    型は特に他者のコードを理解する時に有用で、チームで仕事をする時に作業がやりやすくなります。
    ただ、Haskellの場合は型推論が強力で、わざわざ書かなくても分かるもの(例えば上記の変更textはわざわざ書かなくてもStringである可能性が高い)は、Haskell側で勝手に推測して型をつけてくれます。

    もちろん自分で型をつけてもエラーにならないので、自明なものに関してはオートで、注釈が必要なものは手動でなどとして、時間を短縮することができます。


    ・静的な型をつけられる
    2番目のメリットと関連するところですが、重要なところなので細かく記載します。
    すでに述べたようにCやJavaなどと同じように、Haskellは静的な型を必要とします。静的に型をつけられるということは、つまり言語がコンパイルされるときにエラーを検出してくれるということです。

    言い換えれば、わざわざテストを書かなくても、大半のエラーは言語側で検出してくれます。
    Haskellの型チェックのおかげで、テストなしでリリースしてもバグが出なかったという話もあるくらいです。

    人によっては細かくエラーを検出するのはデメリット(JavaScriptだと10個エラーが出ると、Javaだと100個エラーが出ると言われることもあります)と捉えますが、個人的にはそれさえクリアすれば安全なプログラムになるのであれば、エラーが初期にたくさん出てくれた方が良いと考えます。

    また、すでに述べたように型推論が強力なので、型を書く時間は削減することができます。
    もちろんメリットもたくさんありますが、デメリットと言いますかHaskellを使う上で大変な部分もあります。

    ・覚えるべきことが多い
    Haskellは純粋関数型言語なので、いい意味でも悪い意味でも手続き型言語とプログラムを作成する上での考え方が異なることがあります。料理のレシピのように1つ1つ手順を書いていくのではなく数学のように全体感を見て必要な関数を記述していくような手順になるので、より抽象化力が問われます。

    特に初心者には少しハードルが高い言語だと言えます。ただ、慣れるとコードの記載量が手続き型言語の数分の1になったりするので、学ぶ価値はあると思います。

    ・副作用をコントロールする必要がある
    関数型言語は副作用をなくす=もともとも書き換えないようにするのが基本の考え方だとすでに伝えましたが、それではInputやOutputなどの値を変更する必要がある場合にはどうすれば良いのでしょうか?

    Haskellの場合はI/Oモナドというものを使って対処します。モナドは非常に難しい概念なのであまり深入りはしませんが、Haskellの場合は値を書き換えたりなど、副作用が発生する際にモナドを使用する必要があります。この辺りも初心者には難しいかもしれません。

    ・メジャーな言語と比べ、人気がそれほどない
    Haskellは1985年からあるかなり古い言語で、良いコミュニティもたくさんありますが、Javaなどと比較すると使っている人の数は多くありません。もし深刻な問題が発生した時、適切な解決策を見つけるのに時間がかかる可能性があります。発見したバグが、誰も体験したことのない未知のバグの可能性もあるからです。

    情報としては十分だと思うので、ここからは実際の使い方に関して見ていきましょう。

    具体例: (Hello worldが画面に出せるようにする)

    1. 環境構築
    Haskell stackのインストール(mac、linuxユーザー向け)
    $ curl -sSL https://get.haskellstack.org/ | sh 

    Haskell stackのインストール(windowsユーザー向け)
    Set-ExecutionPolicy Bypass -Scope Process -Force;[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072;Invoke-Command -ScriptBlock ([ScriptBlock]::Create((Invoke-WebRequest https://www.haskell.org/ghcup/sh/bootstrap-haskell.ps1 -UseBasicParsing))) -ArgumentList $true

    このstackというのが、Haskellを動かすパッケージマネージャー(Rubyだとrbenv, Nodeだとnodebrew, Pythonだとpyenvのようなもの)です。厳密に言うとstackを使わなくともHaskellを動かせる様ですが、これが最も簡単な方法な様なのでこの方法で進めます。


    もし他のやり方なども興味があれば、公式のドキュメントをご覧ください(下の参考資料の項目にリンクを載せます)


    特徴の部分でお伝えした通り、Haskellは静的型付け言語なので、コンパイラが必要になります。

    GHCというコンパイラをインストールするため、stackを用いた以下のコマンドを入力します。そうするとGHCのインストールが完了します。

    stack setup

    GHCがインストールされているか確認するために、以下のコマンドを入力します。バージョン情報が出ればインストールは完了です。
    stack ghc -- --version
    
    
    //result
    The Glorious Glasgow Haskell Compilation System, version 9.0.2

    2. プロジェクトを作成します。場所は好きなところで構いません。Haskellのフォルダを作成し、その中に以下のようなhello.hs ファイルを作成します。

    main :: IO ()
    main = putStrLn "Hello, world!"

    上記でmainと書かれている部分が、functionにあたります。Cやgolangなどもそうですが、このmain functionは非常に重要で、常に1つ必要になります。また、プログラムをコンパイルする時に一番先にコンパイルされる部分でもありますので覚えておくと良いかもしれません。
    他のプログラミング言語だと'='は変数を表すことが多いのですが、Haskellの場合はfunctionも'='で表します。なので、よりシンプルに記載できますね。putStrLnはビルトインの関数でPythonの'print', JavaScriptの'console.log'にあたります。特徴の部分でお伝えした通り、入出力など値を変化させる必要がある時はIO()が必要になります。

    3. 2で作成したhello.hs fileを、以下のコマンドでコンパイルしてください。そうすると、3つの異なるファイル(hello, hello.hi, hello.o)がバイナリファイルとして生成されます
    stack ghc hello.hs

    4. 3でコンパイルした中で、後ろに何もついていないファイル(この場合はhello)を以下のコマンドで動かします。そうすると、コンソールにちゃんとHello, world!が出力されていることがわかります。

    ./hello
    Hello, world!

    まとめ

    Haskellの特徴と使い方を紹介しました。非常にシンプルな例なのであまり良さが伝わらないかもしれませんが、例えばフィボナッチ数列(1, 1, 2, 3, 5, 8 など、「どの数字も前2つの数字を足した数字」)を扱う際には、JavαやJavaScriptを使うと10行以上かかるところがHaskellだと1行で書けたりします。
    慣れれば非常に強力な武器になりますし、何より抽象的な思考の練習になるのでHaskellで自在にコードを書ける様になれれば他の言語もよりうまく扱えるようになるかもしれませんね。

    参考資料

    公式サイト(Haskell): https://www.haskell.org/
    What is Haskell, and who should use it?: https://www.47deg.com/blog/what-is-haskell/
    純粋関数型言語Haskellを使ってみた: https://qiita.com/k-iida/items/8023f55dec2d3c3c73f7
    Haskellらしさって? 「型」と「関数」の基本を解説!(第二言語としてのHaskell): https://eh-career.com/engineerhub/entry/2017/08/25/110000/?PK=F85EE5&isLoginAfter

    最後までお読みいただき、ありがとうございました!
    PREV
    2022.11.10
    UXを豊かにするハニカム構造
    NEXT
    2022.11.10
    Javascript Arrays