Gleamで湯婆婆を実装してみる

#1.はじめに

令和時代の"Hello world"と呼ばれる（？）湯婆婆実装シリーズに便乗してみました。

 - [原作者@Nemesis様](https://qiita.com/Nemesis/items/c7192a7c510788d2cba2)
 - [湯婆婆実装シリーズまとめ](https://qiita.com/torifukukaiou/items/c8361231cdc56e493245)（？）

この記事では、**[Gleam](https://gleam.run/)**という言語での実装にチャレンジしました。

Gleamについてご存じない方は、こちらを参照頂けると幸いです。
→　[Gleam (Rust + Erlang) 事始め](https://qiita.com/myasu/items/e4d038f15557a0723b35)


#2.実装例

##(1)プロジェクトの作成

```bash:コマンドライン
$ gleam new yubaba
* creating yubaba/LICENSE
* creating yubaba/.gitignore
* creating yubaba/README.md
* creating yubaba/gleam.toml
* creating yubaba/test/yubaba_test.gleam
* creating yubaba/src/yubaba.gleam
* creating yubaba/.github/workflows/test.yml
* creating yubaba/rebar.config
* creating yubaba/src/yubaba.app.src

Your Gleam project "yubaba" has been successfully created.
The rebar3 program can be used to compile and test it.

    cd yubaba
    rebar3 eunit
```

##(2)コード

標準入力の関数が無いようなので、名前の入力は、関数の引数に直接与えています。

また、”名前を奪う”ために、ランダムにN文字目を取り出す処理が、かなり回りくどい書き方になってます・・・

```rust:src/yubaba.gleam
import gleam/float
import gleam/int
import gleam/io
import gleam/result
import gleam/string

pub fn hello_world() -> String {
  "Hello, from yubaba!"
}

//0.0～1.0の間でFloat型の乱数を返す
//https://gleam.run/book/tour/external-functions.html
pub external fn random_float() -> Float = "rand" "uniform"

//湯婆婆関数
pub fn yubaba(name:String) {

  //文字の長さを取得
  let name_length = int.to_string(string.length(name))

  //何文字目を切り出すか乱数で決める：その１
  //※to_float関数がまだ実装されてないのでダメでした
  //  https://hexdocs.pm/gleam_stdlib/gleam/int/#to_float
  //let name_num = int.to_float(name_length) *. name_length
  
  //何文字目を切り出すか乱数で決める：その２
  //※回りくどいけど、なんとかできた･･･

  //”文字列の長さの値”を、一旦文字列に変換して、小数点を付ける
  let length_1 = string.concat([name_length, ".0"])
  //”小数点付きの文字列長”の文字列を、floatに変換。unrap関数で値と成功/失敗値を分割
  let length_2 = result.unwrap(float.parse(length_1), 0.0)
  //乱数の値と、文字列長を掛けて、何文字目を取り出すかを決める
  let name_num = float.round(float.floor(random_float() *. length_2))
  
  //名前を1文字切り出す
  let name_new = string.slice(from: name, at_index: name_num, length: 1)

  //湯婆婆のメッセージ
  io.println("\n■■■ Gleamで湯婆婆を実装してみる ■■■\n")
  io.println("契約書だよ。そこに名前を書きな。\n")
  io.println(string.concat([" > ", name, "\n"]))
  io.println(string.concat(["フン。", name, "というのかい。贅沢な名だねぇ。\n"]))
  io.println(string.concat(["今からお前の名前は", name_new, "だ。いいかい、",
      name_new, "だよ。分かったら返事をするんだ、" , name_new, "!!\n"]))

  //何文字目を切り取ったかの値を返す
  name_num
}
```

##(3)実行例

 1. `rebar3 shell`でコンパイル、対話モードに入ります。
 2. プロンプトに`yubaba:yubaba("yourname").`を入力してEnterします。（今回の実装だと、全角はだめっぽい）
 3. 湯婆婆に名前を奪われます。

```bash:コマンドライン
$ rebar3 shell
===> Verifying dependencies...
Compiling gleam/otp/port
･･･（省略）･･･
Done!
===> Analyzing applications...
===> Compiling yubaba
Erlang/OTP 22 [erts-10.5.4] [source] [smp:4:4] [ds:4:4:10] [async-threads:1] [hipe]

Eshell V10.5.4  (abort with ^G)

1> yubaba:yubaba("myasu").  
■■■ Gleamで湯婆婆を実装してみる ■■■
契約書だよ。そこに名前を書きな。
 > myasu
フン。myasuというのかい。贅沢な名だねぇ。
今からお前の名前はaだ。いいかい、aだよ。分かったら返事をするんだ、a!!
2

2> yubaba:yubaba("myasu").
■■■ Gleamで湯婆婆を実装してみる ■■■
契約書だよ。そこに名前を書きな。
 > myasu
フン。myasuというのかい。贅沢な名だねぇ。
今からお前の名前はyだ。いいかい、yだよ。分かったら返事をするんだ、y!!
1

3> yubaba:yubaba("pomu"). 
■■■ Gleamで湯婆婆を実装してみる ■■■
契約書だよ。そこに名前を書きな。
 > pomu
フン。pomuというのかい。贅沢な名だねぇ。
今からお前の名前はuだ。いいかい、uだよ。分かったら返事をするんだ、u!!
3
```

#4.まとめ

Gleamの勉強がてら（？）試してみました。
悩ましいところが多々あるので、ぼちぼちと直していきます・・・

#参考資料

 - https://gleam.run/cheatsheets/gleam-for-elixir-users/
 - https://gleam.run/book/tour/
 - https://hexdocs.pm/gleam_stdlib/