HaskellでWebアプリケーションを開発する

こんにちは！
Waffle College 2期生の [こはる](www.linkedin.com/in/koharu-saeki) です！
どんな内容ならみんなと被らないだろう。。。と悩んだ結果、最近よく触っているHaskellのWebアプリケーションフレームワークYesodについて書くことにしました🙌


# そもそもHaskellとは？

公式ドキュメントでもHaskellの入門として紹介されている [Learn You a Haskell for Great Good!](https://learnyouahaskell.github.io/introduction.html#so-whats-haskell) によると、Haskellは以下のような特徴を持つと書かれています。
> - Haskell is a **purely functional programming language**. 
> - Haskell is **lazy**.
> - Haskell is **statically typed**. 
> - Haskell uses a very good type system that has **type inference**. 
> - Haskell is **elegant and concise**. 

つまり、純粋関数型言語で、遅延評価・静的型付けを採用していて、型推論システムを持つ簡潔で優雅な言語です！！（？？？？？）
本記事ではHaskellについての詳しい解説は省きますが、もし興味のある人はぜひ以下のサイトとか見てみてください👀❤️‍🔥
- [Real World Haskell](https://book.realworldhaskell.org/read/)
- [Why Haskell matters](https://wiki.haskell.org/Why_Haskell_matters)

# Yesod
Yesodはプログラミング言語Haskellに基づくWebアプリケーションフレームワークです。
Webアプリ開発といえば、JavaScriptやRuby、Java、Python、Goなどですよね。
、、、でもHaskellでWebアプリ作れたらカッコよくないですか？🥺 というわけでYesodを使って簡単なWebアプリを作る方法をざっっっっくりとご紹介します！

# 環境構築
[公式ドキュメント](https://www.yesodweb.com/page/quickstart)に沿って環境構築していきます。

### 1\. Stackをインストール
Stackとは、依存関係を管理してくれるHaskellのビルドツールです。
以下のスクリプトを実行してインストールします。

```sh
$ curl -sSL https://get.haskellstack.org/ | sh 
```


### 2\. 新規プロジェクトの作成
sqliteというYesodのテンプレートを使用して、my-projectという新しいHaskellプロジェクトを作成します。[Yesodテンプレートrepo](https://github.com/yesodweb/stack-templates) によると他にはmaster, postgresなどのテンプレートがあるみたいですね👀
```sh
$ stack new my-project yesodweb/sqlite && cd my-project
```

### 3\. コマンドラインツールをインストール
Yesodフレームワークを使うためのコマンドラインツールyesod-binをインストールします。
`--install-ghc`というオプションをつけることでコンパイラGHCを自動でインストールしてくれます。
```sh
$ stack install yesod-bin --install-ghc
```

### 4\. ビルドして確認
エラーが出なければOK!
```sh
$ stack build
```

### 5\. サーバを立ち上げる
```sh
$ stack exec -- yesod devel
```

### 6\. サイトを確認

http://localhost:3000/ にアクセスし、以下のページが表示されたら成功です👏❤️‍🔥ﾜｰｲ
![2024-12-10 1.12の画像.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3784072/fd5b7266-ffe9-7095-d236-b19c15310dd3.jpeg)


# 実際に作ってみる
### Hello World!
以下のコードを先ほどのmy-project/app/ に `helloworld.hs` として保存します。
```Haskell:helloworld.hs
{-# LANGUAGE OverloadedStrings     #-}
{-# LANGUAGE QuasiQuotes           #-}
{-# LANGUAGE TemplateHaskell       #-}
{-# LANGUAGE TypeFamilies          #-}
import           Yesod

data HelloWorld = HelloWorld

mkYesod "HelloWorld" [parseRoutes|
/ HomeR GET
|]

instance Yesod HelloWorld

getHomeR :: Handler Html
getHomeR = defaultLayout [whamlet|Hello World!|]

main :: IO ()
main = warp 3000 HelloWorld
```
以下のコマンドで実行すると
```sh
$ stack runghc app/helloworls.hs
```
👏 Hello World! 👏
![スクリーンショット 2024-12-10 1.20.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3784072/af15fcd8-c713-48bc-9762-20dd08c63518.png)

簡単にコードの説明をします。流れとしてはこんな感じです。
`helloworld.hs` が実行されるとwarp関数によりポート番号3000にサーバが立ち上がる。
http://localhost:3000/ からこのアプリケーションにアクセスすると（＝ホーム/にアクセスすると）getHomeR関数が実行される。
getHomeR関数は以下のHTMLと同様の内容を表示させる。
```HTML:
<!DOCTYPE html>
<html><head><title></title></head><body>Hello World!</body></html>
```

とりあえずYesodはHaskellファイル内で`[whamlet|...|]`を使えばHTMLを扱えるようにすることができるやつなんだ〜！という認識でOKです(◜‧̮◝ )


### CSS
Webアプリを作るならHTMLの他にCSSも必要不可欠ですよね。実はLuciusというCSSのテンプレート言語を用いることでHaskellでCSSも書けちゃうんです！
Hello World!をもっと可愛くしてみましょう。

先ほどのコードに数行加えます。

```Haskell:helloworld.hs
{-# LANGUAGE OverloadedStrings     #-}
{-# LANGUAGE QuasiQuotes           #-}
{-# LANGUAGE TemplateHaskell       #-}
{-# LANGUAGE TypeFamilies          #-}
import           Yesod
import Text.Lucius (luciusFile)

data HelloWorld = HelloWorld

mkYesod "HelloWorld" [parseRoutes|
/ HomeR GET
|]

instance Yesod HelloWorld

getHomeR :: Handler Html
getHomeR = do
    css <- withUrlRenderer $(luciusFile "app/template.lucius")
    defaultLayout $ do
        toWidget css
        [whamlet|
            <h1>Hello World!
        |]

main :: IO ()
main = warp 3000 HelloWorld
```

そしてappの下に`template.lucius`というファイルを作ります。ここでCSSの処理を書きます。
```CSS:template.lucius
@import url('https://fonts.googleapis.com/css2?family=Sacramento&display=swap');

h1 {
    color: #FFFFFF;
    font-family: 'Sacramento', cursive;
    font-size: 100px;
    text-align: center;
}

body {
    background-color: #FF99CC;
}
```
もう一度 `stack runghc app/helloworls.hs` コマンドで実行してみましょう。

![スクリーンショット 2024-12-10 2.15.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3784072/0bed59c1-85d6-5f43-5546-2bf3df4345ae.png)

かわいすぎる〜〜〜！！！！！🩷🩷
Hello World!がCSSのおかげでとってもかわいくなりました。`template.lucius`内にCSS処理を書き、それを読み込むことでHaskell内でCSSを使うことができました。


### JavaScript
てことはなんかJavaScriptもHaskellで扱えそうな気がしてきました。その通りです。JuliusというJavaScriptのテンプレート言語を使います。

先ほどの`helloworld.hs`、`template.lucius`に数行ずつコードを加えます。
```Haskell:helloworld.hs
{-# LANGUAGE OverloadedStrings     #-}
{-# LANGUAGE QuasiQuotes           #-}
{-# LANGUAGE TemplateHaskell       #-}
{-# LANGUAGE TypeFamilies          #-}
import           Yesod
import Text.Lucius (luciusFile)
import Text.Julius (juliusFile)

data HelloWorld = HelloWorld

mkYesod "HelloWorld" [parseRoutes|
/ HomeR GET
|]

instance Yesod HelloWorld

getHomeR :: Handler Html
getHomeR = do
    css <- withUrlRenderer $(luciusFile "app/template.lucius")
    js <- withUrlRenderer $(juliusFile "app/template.julius")
    defaultLayout $ do
        toWidget css
        toWidget js
        [whamlet|
            <h1 id="floating-text">Hello World!
        |]

main :: IO ()
main = warp 3000 HelloWorld
```

```CSS:template.lucius
@import url('https://fonts.googleapis.com/css2?family=Sacramento&display=swap');

h1 {
    color: #FFFFFF;
    font-family: 'Sacramento', cursive;
    font-size: 100px;
    text-align: center;
}

body {
    background-color: #FF99CC;
}

@keyframes float {
    0% { transform: translateY(0); }
    50% { transform: translateY(-40px); }
    100% { transform: translateY(0); }
}

#floating-text {
    animation: float 3s infinite;
    margin-top: 100px;
}
```

そしてappの下に`template.julius`というファイルを作ります。ここにJSの処理を書きます。
```JavaScript:template.julius
document.addEventListener("DOMContentLoaded", function() {
    const text = document.getElementById("floating-text");
    text.addEventListener("mouseover", function() {
        text.style.color = "red";
        text.style.transition = "color 0.5s";
    });
    text.addEventListener("mouseout", function() {
        text.style.color = "#FFFFFF";
    });
});
```

もう一度 `stack runghc app/helloworls.hs` コマンドで実行してみましょう。

![gif_js.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3784072/162146e8-8013-f501-21e1-841cc33592b9.gif)

❤️🩷かわいすぎる〜〜〜！！！！！🩷❤️
原理的には先ほどのCSSと同じです。JSを使うことによってHello World!をぷかぷか浮かせてマウスオーバー処理を加えることができました。
他にもデータベースと接続したり、フォーム使ったり、デプロイしたり、、、とYesodを使えば色々実装できるので興味を持った方は見てみてください！
- [Yesod Web Framework Book](https://www.yesodweb.com/book)


# どうしてHaskell?
どうしてこんな面倒くさいことをしてまでHaskellでWebアプリを作る必要があるのでしょうか。わたしはただ、既存のHaskellのシステムを触るためのGUIシステムを開発するために使い始めただけですが、個人的には以下の理由があるかなと思います。
- 高速なアプリケーションを構築できる
    - Haskellは静的型付きでコンパイルされるため、Yesodも処理が高速
- 堅牢なシステムを構築できる
    - URLを文字列として手動ではなくHaskellの型システムを利用して組み立てることによって、安全にURLを生成できる
    - ハンドラー関数とURLを自動で対応づけてくれるのでルーティング処理が自動で行われる

# 終わり
普段はもう少しスケールの小さい記事を書くことが多いので、技術をざっくばらんに紹介するこういった記事を書くのってとても難しいなと思いました。（いつも書いてくれている世界中の皆様にびっぐ感謝。。。。。）
ほへーHaskellっていう言語でもWebアプリ開発できるんだーふむふむとなってくれれば本望です。まだまだ勉強途中なので、何かあればコメントお願いしますっ🥳

ありがとうございました！

明日以降の記事も楽しみだーーーーー！！！！！