Unison で Welcome to AtCoder を解いてみた

[Qiita Engineer Festa 2024（キータ・エンジニア・フェスタ 2024） - Qiita](https://qiita.com/official-campaigns/engineer-festa/2024)
において、約1ヶ月で38記事という大量の記事の投稿を要求されることがわかった。
そこで、あまりコストをかけずに記事数を稼ぐ方法を考えた結果、「Welcome to AtCoder を様々な言語で解く」ことを思いついた。
単に解くだけでなく、使用する言語仕様の解説を入れれば、記事として一応成立するだろう。

# Welcome to AtCoder

[PracticeA - Welcome to AtCoder](https://atcoder.jp/contests/abs/tasks/practice_1)

Welcome to AtCoder では、以下の形式で整数 $a$, $b$, $c$ および文字列 $s$ が入力として与えられる。

```text
a
b c
s
```

この入力をもとに、与えられた整数の和 $sum = a + b + c$ および文字列 $s$ を、以下の形式で出力することが求められる。

```text
sum s
```

# 今回用いる Unison の機能

## main 関数

[Hello World](https://www.unison-lang.org/docs/#hello-world)
[Delayed computation syntax](https://www.unison-lang.org/docs/#delayed-computation-syntax)

以下の形式で `main` 関数を定義すると、これを実行することでプログラムを実行してくれる。

```
main : '{IO,Exception} ()
main _ =
  処理内容
```

## 関数定義

[Functions · Unison programming language](https://www.unison-lang.org/docs/fundamentals/values-and-functions/functions/)

以下の形式で、引数を1個とる関数を定義できる。

```
関数名 : 引数の型 -> 戻り値の型
関数名 引数名 =
  処理内容
```

インデントの深さによってコードのブロックが認識されるので、同じブロックではインデントの深さを合わせなければならない。

## 変数への値の割り当て

[Blocks and statements · Unison programming language](https://www.unison-lang.org/docs/language-reference/blocks-and-statements/)
[Tuple patterns](https://www.unison-lang.org/docs/language-reference/match-expressions-and-pattern-matching/#tuple-patterns)

以下の形式で、変数に値を割り当てることができる。

```
変数名 = 値
```

以下のようにすると、タプルを分解し、各要素をそれぞれの変数に割り当てることができる。

```
(変数名1, 変数名2) = 値
```

## 整数の処理

[`Nat` 型](https://share.unison-lang.org/@unison/website/code/main/latest/types/lib/base/Nat)は、64ビットの非負整数を表す。
`0` などの符号が無い整数リテラルは、この型である。

[`Nat.+`](https://share.unison-lang.org/@unison/website/code/main/latest/terms/lib/base/Nat/%2B) を用いると、数値の加算ができる。
これは

```
1 Nat.+ 2
```

のように中置で用いる。

[`Nat.toText`](https://share.unison-lang.org/@unison/website/code/main/latest/terms/lib/base/Nat/toText) を用いると、数値をそれを表す文字列に変換できる。

[`Nat.fromText`](https://share.unison-lang.org/@unison/website/code/main/latest/terms/lib/base/Nat/fromText) を用いると、文字列をそれを表す数値に変換できる。
`Nat.fromText` は、直接 `Nat` を返さず、`Optional Nat` を返す。
以下のようにすると、`Optional Nat` 型の値 `value` から `Nat` 型の値 `x` を取り出すことができる。

```
match value with
  Optional.None -> 0
  Some x        -> x
```

(参考：[Constructor patterns](https://www.unison-lang.org/docs/language-reference/match-expressions-and-pattern-matching/#constructor-patterns))

## 文字列の処理

[`Text.++`](https://share.unison-lang.org/@unison/website/code/main/latest/terms/lib/base/Text/%2B%2B) を用いると、文字列を結合できる。
これは

```
"a" Text.++ "b"
```

のように中置で用いる。
(参考：[Text](https://share.unison-lang.org/@unison/website/code/main/latest/types/lib/base/Text))

[`break isSpace`](https://share.unison-lang.org/@unison/website/code/main/latest/terms/lib/base/Text/break) を用いると、文字列を最初の空白で分割した文字列のタプルを得ることができる。

## 標準入出力

[`readLine ()`](https://share.unison-lang.org/@unison/website/code/main/latest/terms/lib/base/IO/console/readLine) を用いると、標準入力から1行読み込み、結果を文字列で得ることができる。
これは、関数 `readLine` に `Unit` 型の値 `()` を渡す操作である。
結果の文字列に改行文字は含まれない。

[`printLine`](https://share.unison-lang.org/@unison/website/code/main/latest/terms/lib/base/IO/console/printLine) を用いると、文字列を標準出力に出力し、さらに改行を出力できる。

# 提出コード

```
textToNat : Text -> Nat
textToNat t =
  match Nat.fromText t with
    Optional.None -> 0
    Some x        -> x

main : '{IO, Exception} ()
main _ =
  line1 = readLine ()
  line2 = readLine ()
  line3 = readLine ()
  a = textToNat line1
  (bstr, cstr) = break isSpace line2
  sum = a Nat.+ (textToNat bstr) Nat.+ (textToNat cstr)
  printLine ((Nat.toText sum) Text.++ " " Text.++ line3)
```

[提出 #55229471 - AtCoder Beginners Selection](https://atcoder.jp/contests/abs/submissions/55229471)