FlandreDaisuki / FlandreDaisuki/github-issue-blog
初學 OCaml
- Dominant language
- No language data
- Stars
- 9
- Forks
- 0
- PR merge metrics
- No merged PRs in 30d
Description
## 起
看起來比較不會弄髒環境的安裝方法:
1. [安裝 `opam`](https://opam.ocaml.org/doc/Install.html)
2. [用 `opam` 安裝 `ocaml`](https://www2.ocaml.org/docs/install.html#OPAM)
```sh
~ $ which ocaml
/home/flandre/.opam/default/bin/ocaml
~ $ ocaml --version
The OCaml toplevel, version 4.12.0
```
為了開發順暢,也要幫 vscode 安裝擴充套件組合擇一:
1. [OCaml and Reason IDE](https://marketplace.visualstudio.com/items?itemName=freebroccolo.reasonml) + [ocaml/merlin](https://github.com/ocaml/merlin#easy-installation-with-opam)
2. [OCaml Platform](https://marketplace.visualstudio.com/items?itemName=ocamllabs.ocaml-platform) + [ocaml/ocaml-lsp](https://github.com/ocaml/ocaml-lsp) (又寫了幾題發現改用這套體驗更好)
安裝結束後重啟 vscode 可以看到 type signature 就完成了

## 承
2020 年底有跟著玩 [Advent of Code](https://adventofcode.com/2020),覺得很適合拿來練手,所以就開了 2018 年想試著用 OCaml 來解。Repo: [advent-of-code/tree/2018](https://github.com/FlandreDaisuki/advent-of-code/tree/2018)。
## 轉
一開始就遇到讀檔,找了很多版本,最後決定用 line stream 來實作:
```ocaml
(* https://ocaml.org/learn/tutorials/streams.html *)
let line_stream_of_channel channel =
Stream.from (fun _ ->
try Some (input_line channel) with End_of_file -> None)
```
解讀的方式是:
1. `try ... with` 一個回傳 `Some` 一個回傳 `None` 那麼 `fun _` 的回傳型別就是 `'a option`。
用泛型來理解就是 `Option`,這邊的 `'a` 就是 `string`。
2. Stream.from 的 signature 是 `(int -> 'a option) -> 'a Stream.t`,帶入 `fun _ -> string option` 會生出 `string Stream.t`
3. 最後理解 `'a Stream.t` 用泛型來解釋就是 `Streamable`
有了輸入就可以讀題目了,題目是每一行字都是帶號整數,求總和。以 JS 為例就是:
```js
const answer1 = lines.map(Number).reduce((a, b) => a + b, 0);
```
那理論上逐行翻譯就能得到答案了,不過因為我們的輸入是 Stream,所以要虛折一點:
```ocaml
(* tutorial 抄來的 *)
let stream_map f stream =
let rec next i =
try Some (f (Stream.next stream))
with Stream.Failure -> None in
Stream.from next
(* tutorial 抄來改的 *)
let stream_fold f init stream =
let result = ref init in
Stream.iter
(fun x -> result := f !result x)
stream;
!result
let line_stream = line_stream_of_channel (open_in "day01.txt")
let int_stream = stream_map int_of_string line_stream
let answer1 = stream_fold ( + ) 0 int_stream
```
其實這樣就能拿到答案了但多看一些其他人的 code 感覺可以再寫得更 OCaml 一點
```ocaml
let answer1 =
let line_stream = line_stream_of_channel (open_in "day01.txt") in
let int_stream = stream_map int_of_string line_stream in
stream_fold ( + ) 0 int_stream
```
大概看到這就有點感覺了,`let ... in` 就像大括號一樣用來表示 scope 在哪
最後要怎麼印出答案呢…找了很久最後才找到要這樣寫
```ocaml
let () = Printf.printf "answer 1: %d" answer1
```
## 合
光寫個讀檔轉數字加總,大概就花了六七個小時,前途堪慮。不過越來越懂什麼叫看 type 寫 code,希望有機會把 2018 的題目全寫完。
Contributor guide
No contributing guide indexed for this repository
Research direction
The issue contains a Chinese OCaml learning article covering opam, VS Code extensions, Advent of Code 2018, streams, and JavaScript comparisons, but names no target file or requested change. First inspect the repository's existing blog or issue-to-post workflow, then determine where this article belongs and what publication format is expected. Done means the agreed article content is integrated without losing its examples and links.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- javascript, ocaml
- Domain
- content, documentation
- Issue type
- Documentation
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Needs clarification
- Newbie friendliness
- 25/100