関数型言語を学ぶ

## なぜHaskellなのか
関数型言語には、`Haskell`、`OCaml`、`Scala`、`F#`、`Clojure`などがあり、`JavaScript`や`Python`でもその考え方は活用できる。
それぞれに特徴があり、実務に対する強さであったり他言語との関連性など様々な要素があるが、**「関数型言語」を学ぶ** ことに重きを置いた場合は**純粋関数型言語の代表格のHaskellに軍配が上がる。**

## Haskellの環境構築
以下を参考に構築する

https://zenn.dev/mod_poppo/articles/haskell-setup-2023

>StackとGHCup, Cabalがそれぞれ何をするツールなのかと言うと、
>
>- Stack: GHCのインストールおよび、プロジェクトのビルドを行う
>- GHCup: GHCや周辺ツール (Cabal/HLS/Stack) のインストールを行う
>- Cabal (cabal-install)[1]: プロジェクトのビルドを行う
>
>となります。役割が被っているために対立して語られるわけです。

>筆者としては、
>
>でかいアプリケーションを書きたいならStack
汎用的なライブラリーを書きたい、あるいは最新のGHCを試したいならCabal
を使うのが良いと考えます。詳しくは後述します。

ということなので、自分も今回は全部入れて設定を切り替えながらプロジェクトごとに利用するものを切り替えていこうと思う。

### GHCupをインストールする
公式：https://www.haskell.org/ghcup/
上のページよりダウンロードが可能であるようだ。

Windowsの場合は、選択すればGHC、Cabal、Stackすべてを一度に入れることも可能とのこと

公式サイトにある以下のようなコマンドをPowerShellに入れることで、自分はダウンロードが始まりました。
```bash
Set-ExecutionPolicy Bypass -Scope Process -Force;[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; try { Invoke-Command -ScriptBlock ([ScriptBlock]::Create((Invoke-WebRequest https://www.haskell.org/ghcup/sh/bootstrap-haskell.ps1 -UseBasicParsing))) -ArgumentList $true } catch { Write-Error $_ }
```

## パッケージ管理の違い
:::note info
cabalはグローバルでインストールされる
一方でstackはプロジェクト単位で管理することが可能である
:::
この違いを考えると、簡単で小規模なプログラムを利用する場合はcabalでパッケージを複数使用する場合などはすべてstackで管理するほうが安全であるだろう

## Haskellの基本
```haskell:hs
-- 関数の定義 Haskellでは、関数は第一級オブジェクトである
add x y = x + y
```
```js:js
// JavaScriptやPythonのように関数を変数に代入したり、ほかの関数の引数として渡したりできる
const add = (x,y)=>{
    return x +y;
}
```
### 例
```haskell
-- 型推論が非常に強力である
add :: Int -> Int -> Int
add x y = x + y

-- #高階関数
-- JavaScriptやPythonのように、関数を引数として受け取ったり、関数を返したりできる
applyTwice :: (a -> a) -> a -> a
applyTwice f x = f (f x)

-- #高階関数
-- リスト処理 HaskellのリストはJavaScriptの配列やPythonのリストに似ていますが、
-- より関数型の操作が可能です。map、filter、foldなどの高階関数を使ってリストを処理します。
doubleList :: [Int] -> [Int]
doubleList xs = map (*2) xs

-- パターンマッチ Haskellのパターンマッチは、条件分岐やデータ構造の分解に使われます。
-- これは、TypeScriptのswitch文やPythonのif-elif-else文に似ていますが、より強力です。
factorial :: Int -> Int
factorial 0 = 1
factorial n = n * factorial (n - 1)
```

## 個別の記法
### 型の書き方
```hs
-- 型推論が非常に強力である
add :: Int -> Int -> Int
add x y = x + y
```
add⇦関数名
最初・２番目のIntはInt型の引数を取得することを示す
最後のIntはInt型を返すことを示している

つまり以下のTypeScriptのコードと同じことを行っている
```ts:ts
const add = (x: number) => (y: number): number => {
    return x + y;
}

// もしくは
const add = function(x: number) {
    return function(y: number): number {
        return x + y;
    };
};

// add(1)(2)
// 3

// const addFive = add(5)
// addFive(10)
// 15
```
:::note info
自分は見慣れない記法であったが、暗黙的に`カリー化`されるHaskellのコードをTypeScriptに起こすとこのようになるようだ
:::

簡単に言うと、Haskellでは関数の引数は1つとすると決まっているため、内部的な処理としては引数を一つずつ持つ関数を連結しているということになる

もし複数の引数を渡す場合は、`タプル型`で渡すとよいとのこと

:::note info
メリットとしては、addFiveのように第１引数を固定化した式を作成することで、オーバーラップしたかのような関数を簡単に作成できる点にある
:::


### 高階関数
```hs:hs
-- JavaScriptやPythonのように、関数を引数として受け取ったり、関数を返したりできる
applyTwice :: (a -> a) -> a -> a
applyTwice f x = f (f x)
```
:::note info
高階関数とは
1. 関数を引数として受け取る関数
1. 関数を返り値として返す関数

言い換えると高階関数は **「関数を操作する関数」** である
:::

#### Map
高階関数を使わない場合
```hs:hs
doubleList :: [Int] -> [Int]
doubleList [] = []
doubleList (x:xs) = (2*x) : doubleList xs
```
高階関数を使う場合
```hs:hs
doubleList :: [Int] -> [Int]
doubleList xs = map (*2) xs
```
map関数を用いて、リストの各要素に`(*2)`関数を適用し、新しい関数を返すことができる

#### Filter
リストをフィルタリングする関数の場合
```hs:hs
evenList :: [Int] -> [Int]
evenList xs = filter even xs
```
filter evenで偶数の要素のみを返す関数を返す

#### 高階関数を使う意義
:::note info
コードの重複を減らし、より汎用的で再利用可能なコードを書くことができる
:::

### パターンマッチ,再帰関数
```hs:hs
-- パターンマッチ Haskellのパターンマッチは、条件分岐やデータ構造の分解に使われます。
-- これは、TypeScriptのswitch文やPythonのif-elif-else文に似ていますが、より強力です。
factorial :: Int -> Int
factorial 0 = 1
factorial n = n * factorial (n - 1)
```
この例では、正の整数の階乗を計算する

この時、以下のコードが最初に評価される

    factorial 0 = 1
引数が0の場合は1を返すものである

引数が0でない場合は、次の式が評価される
    
    factorial n = n * factorial (n - 1)

この式では、3に対する式を計算すると次のようになる

    factorial 3 = 3 * factorial 2 
                = 3 * (2 * factorial 1) 
                = 3 * (2 * (1 * factorial 0)) 
                = 3 * (2 * (1 * 1)) 
                = 3 * (2 * 1) 
                = 3 * 2 
                = 6

## 一応のまとめ
HaskellをHello Worldしたばかりの身にとっては何を言っているのか正直わからないものが多いと感じた。
`{`と`}`を使わない記法も含めて、シンプルさを追求した弊害ともいうべき初学者に対する難しさがあると感じた、、、

ひとまずこれまでの言語で学んできたAPIの作成を通して、言語的な特徴や基本的な記法を学んでいきたいと思う
オブジェクト指向とは違った抽象化と汎用化の手法は面白い反面、クソほどとっつきにくい