Tcl・R・Golang・RustなどでFizzBuzzやった時のメモ・感想

# Tcl・R・Golang・RustなどでFizzBuzzやった時のメモ・感想

学部のとある講義に参加させてもらった際にいろいろな言語でFizzBuzzを書くことをしていた。
本稿はその時のメモや感想。
(別の回ではPostScriptで書いてたとか…)

扱った言語は以下。

* Tcl
* R
* Golang
* Rust
* ZSH
* SQLite3
* Ruby

ZSHやSQLite3、Ruby以外は全て初めて触った。
上記の3つの言語は書き方に工夫されていたが、琴線に触れたのは、
SQLite3だけだったのでそちらだけ記載。

## Tcl

### インストール

```shell-session
$ apt install tcl-dev/stable
```

### サンプルコード

```tcl:fizzbuzz.tcl
#!/usr/bin/tclsh

for {set i 1} {$i <= 40} {incr i} {
    if {$i%15==0} {
        puts FizzBuzz
    } elseif {$i%5==0} {
        puts Buzz
    } elseif ($i%3==0) {
        puts Fizz
    } else {
        puts $i
    }
}
```

初っ端がTclなのはだいぶハードルが高かった。
基本文字列型しかなく、文字列を書くのにクォートなしでも良いのが特徴的。
ブランクを入れる時はクォートが必要。クォートが{}とかいうのが…(-_-;)
演算をする際はexprを使う必要があるようだが、
ifの条件式の場合はexprなしでも良いようだった(バージョンによる？)。
{}と{}の間にブランクがないと構文エラーとかになるのも慣れなかった。

## R

FizzBuzz書くぐらいならシンプルだった。

### インストール

```shell-session
$ apt install r-base/stable
```

### サンプルコード

```r:fizzbuzz.r
#!/usr/bin/Rscript

for (i in 1:40) {
  if (i%%15==0){
    print("FizzBuzz")
  }else if (i%%5==0){
    print("Buzz")
  }else if (i%%3==0){
    print("Fizz")
  }else{
    print(i)
  }
}
```

上記のコードでは全行に[1]が出るのが特徴だった。
なんでも入力や出力のデータ数が頭につくらしい。
以下のように対話的にscan()を実行すると分かりやすかったが。

```R
> scan()
1: 1 2 3
4: 4 5 6 7 8
9: 9 10
11: 
Read 10 items
 [1]  1  2  3  4  5  6  7  8  9 10
```

## Golang

### インストール

```shell-session
$ wget https://redirector.gvt1.com/edgedl/go/go1.9.2.linux-amd64.tar.gz
```

```shell-session
$ tar -C /usr/local -xzf go1.9.2.linux-amd64.tar.gz
```

### 実行方法

```shell-session
$ /usr/local/go/bin/go run fizzbuzz.go
```

ビルドしてから実行する場合は以下。

```shell-session
$ /usr/local/go/bin/go build fizzbuzz.go
$ ./fizzbuzz
```

他のサブコマンドは、cleanとfmtを試した。
cleanはmakeやmvnのclean的な用途で、fmtはインデントの修正。
(スタイルが統一されるのは個人的には好感が持てた)

### サンプルコード

以下のページを参考にするだけでイケた。

http://golang.jp/go_spec

```golang:fizzbuzz.go
package main

import (
	"fmt"
)

func main() {
	var i int = 0
	for i = 1; i < 40; i++ {
		if i%15 == 0 {
			fmt.Println("FizzBuzz")
		} else if i%5 == 0 {
			fmt.Println("Buzz")
		} else if i%3 == 0 {
			fmt.Println("Fizz")
		} else {
			fmt.Println(i)
		}
	}
}
```

以前本で読んで型を後ろに書くのは知ってたので、
それほど抵抗はなかった。
ビルドした際にライブラリなどが取り込まれたのは結構びっくりしたところ。
ぐぐったらこんな記事見つかった。

https://qiita.com/Jxck_/items/02185f51162e92759ebe

チャンネルとか触ると難しい？ 名前しか知らないが。

## Rust

### インストール

```shell-session
$ curl https://sh.rustup.rs -sSf | sh
```

### プロジェクトセットアップ

```shell-session
$ USER=yhornisse $HOME/.cargo/bin/cargo new hello
```
rootでやってUSERが空だとエラーになった。

```shell-session
$ USER=yhornisse $HOME/.cargo/bin/cargo run src/main.rs
```

### サンプルコード

```rust:fizzbuzz/src/main.rs

fn main() {
  for i in 1..40 {
    if (i%15==0){
      println!("FizzBuzz");
    }else if (i%3==0){
      println!("Fizz");
    }else if (i%5==0){
      println!("Buzz");
    }else{
      println!("{}", i);
    }
  }
}
```

FizzBuzzレベルなら比較的簡単だったが、いろいろやろうとするとなかなか厄介だった。
特に所有権周りは、ぱっと見て分かるようなものではなかった。

https://doc.rust-jp.rs/book/second-edition/ch04-00-understanding-ownership.html

また、変数定義(let)のデフォルトは定数らしく、
可変(mutable)にするにはmutを指定する必要があるとか。
(変数定義と言っていいか微妙だが)

```rust
  let mut i = 0;
```

## SQL (SQLite3)

### サンプルコード

講義の中では手続き型っぽくない書き方も出たが、
そちらは自分の琴線に触れなかった。
それよりもWITHを使った再帰が衝撃的だったのでそちらを記載。

```sql:fizzbuzz.sql
WITH num AS (
  SELECT 1 AS n
    UNION ALL
  SELECT n+1 FROM num WHERE n < 40
)
SELECT
 CASE
    WHEN n%15==0 THEN
      'FizzBuzz'
    WHEN n%5==0 THEN
      'Buzz'
    WHEN n%3==0 THEN
      'Fizz'
    ELSE
      n
 END
FROM
 num
ORDER BY '0' & n /* SQLiteだと全て文字列なので */
```