F#で言語処理100本ノック 第1章

急にF#が書きたくなったのでよく見かける言語処理100本ノックをやりました.
始めて3日ほどなので良い書き方を教えていただきたいです.

問題はこちらです.
http://www.cl.ecei.tohoku.ac.jp/nlp100/

今回は手軽に書いて実行できるF# Interactiveを使いました.

## 環境
- .NET Core v3.0.0-preview6
- F# 4.6

## 本題
### 00. 文字列の逆順
```fsharp
let stringReverse (str : string) =
    str
    |> Seq.rev
    |> Seq.map string
    |> String.concat ""

stringReverse "stressed" |> printfn "%s"
// desserts
```

### 01. 「パタトクカシーー」
```fsharp
let getOddIndices (str : string) =
    seq {
        for i in 0..str.Length - 1 do
            if i % 2 = 1 then yield str.[i]
    }
    |> Seq.map string
    |> String.concat ""

getOddIndices "パタトクカシーー" |> printfn "%s"
// タクシー
```

### 02. 「パトカー」＋「タクシー」＝「パタトクカシーー」
```fsharp
let stringConcat (str1 : string) (str2 : string) =
    let minLength = Array.min [| str1.Length; str2.Length |]
    seq {
        for i in 0..minLength - 1 -> string str1.[i] + string str2.[i]
    }
    |> Seq.reduce (+)

stringConcat "パトカー" "タクシー" |> printfn "%s"
// パタトクカシーー
```

### 03. 円周率
```fsharp
let decomposeAndCount (str : string) = str.Split(' ') |> Seq.map String.length

"Now I need a drink, alcoholic of course, after the heavy lectures involving \
quantum mechanics."
|> decomposeAndCount
|> printfn "%A"
// seq [3; 1; 4; 1; ...]
```

### 04. 元素記号
```fsharp
let genElemMap (l : int []) (str : string) =
    let s = str.Split(' ')
    seq {
        for i in 1..s.Length do
            if Seq.contains i l then yield string s.[i - 1].[0]
            else yield s.[i - 1].[0..1]
    }
    |> Seq.zip (seq {
                    for i in 1..s.Length -> i
                })
    |> Map.ofSeq

let singleList = [| 1; 5; 6; 7; 8; 9; 15; 16; 19 |]

"Hi He Lied Because Boron Could Not Oxidize Fluorine. New Nations Might Also \
Sign Peace Security Clause. Arthur King Can."
|> genElemMap singleList
|> printfn "%A"
// map
//  [(1, "H"); (2, "He"); (3, "Li"); (4, "Be"); (5, "B"); (6, "C"); (7, "N"); (8, "O"); (9, "F"); ...]
```

### 05. n-gram
```fsharp:task5.fsx
let makeNGram (n : int) (sequence : seq<_>) =
    let s = Seq.toList sequence
    seq {
        for i in 0..s.Length - n -> s.[i..i + n - 1]
    }

// word n-gram
"I am an NLPer".Split(' ')
|> makeNGram 2
|> printfn "%A"
// string n-gram
"I am an NLPer"
|> makeNGram 2
|> printfn "%A"
// seq [["I"; "am"]; ["am"; "an"]; ["an"; "NLPer"]]
// seq [['I'; ' ']; [' '; 'a']; ['a'; 'm']; ['m'; ' ']; ...]
```

### 06. 集合
上で作った`makeNGram`を利用しています.
F# Interactiveでは `#load "hoge.fsx"`として別ファイルを読み込んで実行できるのですが, 関数のみを読み込んだり, 或いはPythonの`if __name__ == '__main__':`のように呼び出された時は実行しないオプションみたいなのはあるのでしょうか...

```fsharp
#load "./task5.fsx"

open Microsoft.FSharp.Collections
open Task5

let x =
    "paraparaparadise"
    |> makeNGram 2
    |> set

let y =
    "paragraph"
    |> makeNGram 2
    |> set

let except x y = x - Set.intersect x y

Set.union x y |> printfn "Union: %A"
except x y |> printfn "Except: %A"
Set.intersect x y |> printfn "Intersect: %A"
// Union: set [['a'; 'd']; ['a'; 'g']; ['a'; 'p']; ['a'; 'r']; ['d'; 'i']; ['g'; 'r']; ['i'; 's']; ['p'; 'a']; ['p'; 'h']; ...]
// Except: set [['a'; 'd']; ['d'; 'i']; ['i'; 's']; ['s'; 'e']]
// Intersect: set [['a'; 'p']; ['a'; 'r']; ['p'; 'a']; ['r'; 'a']]

```

### 07. テンプレートによる文生成
```fsharp
let generateTemplate x y z = string x + "時の" + string y + "は" + string z

generateTemplate 12 "気温" 22.4 |> printfn "%s"
// 12時の気温は22.4
```

### 08. 暗号文
```fsharp
open System

let reverseLowerCase c = 219 - int c |> char

let cipher str =
    str
    |> Seq.map (function
                | c when Char.IsLower c -> reverseLowerCase c
                | c -> c
                >> string)
    |> Seq.reduce (+)

"Hello F#!"
|> cipher
|> printfn "%s"
// Hvool F#!
```

### 09. Typoglycemia
```fsharp
open System

let permuteWord str =
    match String.length str with
    | n when n <= 4 -> str
    | n ->
        let rnd = Random()

        let middle =
            str.[1..n - 2]
            |> Seq.sortBy (fun _ -> rnd.Next())
            |> Seq.map string
            |> Seq.reduce (+)
        string str.[0] + middle + string str.[n - 1]

let typoglycemia (str : string) =
    str.Split(' ')
    |> Seq.map permuteWord
    |> String.concat " "

"I couldn't believe that I could actually understand what I was reading : the phenomenal power of the human mind ."
|> typoglycemia
|> printfn "%s"
// I cun'odlt believe that I cluod altulcay utnaesrdnd what I was ranideg : the paennoehml power of the huamn mind .
```