YAMAMOTO Yuji (山本悠滋)
2025-06-15 関数型まつり 2025
Haskell以前における純粋関数型言語の代表、Miranda最新版(2020年リリース‼️)のマニュアル曰く…
read :: [char]->[char]など
Report on the Programming Language Haskell Version 1.0より:
Haskell’s I/O system is based on the view that a program communicates to the outside world via streams of messages:
Report on the Programming Language Haskell Version 1.0より:
Responseのリスト(ストリーム)を受け取って、Requestのリスト(ストリーム)を返す関数
Request: 外の世界に送る命令Response:
外の世界から渡されるRequestの結果Requestに応じて引数のResponseが変わるという、直感に反する挙動
Responseを受け取ってRequestを返す」だけの純粋な関数に収まっている
data Request =
ReadFile String
| WriteFile String String
| ReadChan String
| AppendChan String String
| GetEnv String
| SetEnv String String
| ...
data Response =
Success
| Str String
| Failure IOError
| ...Dialogueを使ったプログラムの例を紹介しますDialogueを使って書いたコードの例

😩引数でパターンマッチした種類のResponseと、対応するRequestの順番が一致してないとダメ!

⏩使いにくいので継続渡しによるラッパーが
⏩継続渡しって?
⏩継続渡しって?
比較的身近な例: JavaScriptのコールバックを受け取る関数
// Promiseも立派な継続渡し
// then メソッドが継続を受け取る
readFile(filePath).then((contents) => {
console.log(contents);
});⏩継続渡しに変換すると型はどう変わる?
// 継続渡しじゃない普通の関数(型定義はTypeScriptの構文)
foo(input: number): string;
// その継続渡しバージョン
foo(input: number, k: (output: string) => void): void先程のプログラムをcontinuation basedで書き換えたもの
main =
appendChan stdout "please type a filename\n" exit (
readChan stdin exit (\userInput ->
let (name : _) = lines userInput in
appendChan stdout name exit (
readFile name
(\ioError ->
appendChan stdout
"can't open file" exit done)
(\contents ->
appendChan stdout contents exit done))))[Response] -> [Request]な関数Report on the Programming Language Haskell Version 1.3より:
The I/O system in Haskell is purely functional, yet has all of the expressive power found in conventional programming languages. To achieve this, Haskell uses a monad to integrate I/O operations into a purely functional context.
Dialogue型はなくなり、代わりにIOという型が登場先程のプログラムを現代のHaskellに(ほぼ)直訳したもの
main = do
putStrLn "please type a filename\n"
userInput <- hGetContents stdin
let (name : _) = lines userInput
putStrLn name
contents <- readFile name
putStrLn contentsdoブロックの中で利用できる
IO は純粋な関数?IO を列挙する際 do
ブロックで囲う必要があったり、<- を使うことIOの正体: それでも純粋っぽい部分 (2)RealWorldを受け取ってRealWorld(と結果となる値)を返す関数をラップしたオブジェクト
ただし!直接実行する機能がない。普通の関数のように呼び出すことができない
IOの正体: それでも純粋っぽい部分 (3)>>=
bind」IOとIOを返す関数を渡すと、それぞれを繋げた新しいIOができるIOの正体: それでも純粋っぽい部分 (4)IOを繋げて「組み立てる」だけ
IOを繋げた結果もまたIOになるので、IOを使っている箇所はみんなIO型の関数になる>>=の例1: IO同士を繋げるdo記法で分かりやすくしたバージョン:
やっぱりこれはダメ:
>>=の例2:
純粋な関数の中からIOを呼んでIOにする (2)その中でIOを呼ぶ
>>=の例2:
純粋な関数の中からIOを呼んでIOにする (3)do記法で分かりやすくしたバージョン:
IOを繋げて「組み立てる」だけ? (1)それを言ったら、他の言語も「命令を列挙している」だけでは?
// JavaScript風の擬似コード
function main() {
print("please type a filename");
const userInput = getInput();
const name = userInput.split("\n")[0];
print(name);
const contents = readFile(name);
print(contents);
}IOを繋げて「組み立てる」だけ? (2)>>=で繋げたIOも、結局はコンパイラーなどを通じて実行する(副作用を起こす)プログラムになるIOを実際に使用するときの体験は他のプログラミング言語で入出力をするときとほぼ同じ<-を使う、など構文の細かい違いがあったり、IOは常にファーストクラスオブジェクト」なのでその分少し機能が多いが…
IOを実際に使用するときの体験は他のプログラミング言語で入出力をするときとほぼ同じIOを実行できるし、
IOはファーストクラスオブジェクトであり、IOを実行する箇所とそうでない箇所をマークして区別できる言語Space, Right Arrow or swipe left to move to next slide, click help below for more details