Implementing functional languages を頑張って読む.3日目

# 3日目

## 1.4

SKIコンビネータとBCKWコンビネータを作る.ちょっと違うけどまあ問題無いだろう.
タプルは構造体にする.
void*は厳しいことがわかったけどこのまま行く.この選択が間違っていませんように.

```
preludeDefs :: CoreProgram
preludeDefs
  = [ ("I", ["x"], EVar "x"),
      ("K", ["x","y"], EVar "x"),
      ("K1",["x","y"], EVar "y"),
      ("S", ["f","g","x"], EAp (EAp (EVar "f") (EVar "x"))
      (EAp (EVar "g") (EVar "x"))),
      ("compose", ["f","g","x"], EAp (EVar "f")
      (EAp (EVar "g") (EVar "x"))),
      ("twice", ["f"], EAp (EAp (EVar "compose") (EVar "f")) (EVar "f")) ]
```

これを

こうして

```c
typedef struct {
	Name name;
	alignas(8) void *arg;
	alignas(8) Expr *expr;
} ScDefn;

typedef ScDefn * Program;

#define mkExprp(t, car, cdr) &(Expr){t, (void *)(car), (void *)(cdr)}
#define EVAR(var) mkExprp(EVar, (var), NULL)
#define ENUM(num) mkExprp(ENum, (num), NULL)
#define ECONSTR(con, str) mkExprp(EConstr, (con), (str))
#define EAP(a, p) mkExprp(EAp, (a), (p))
#define ELET(le, t) mkExprp(ELet, (le), (t))
#define ELETREC(let, rec) mkExprp(ELetrec, (let), (rec))
#define ECASE(ca, se) mkExprp(ECase, (ca), (se))
#define ELAM(la, m) mkExprp(ELam, (la), (m))
Program preludeDefs = (ScDefn[]){
	{"I", (void*)((Name[]){"x"}), EVAR("x")},
	{"K", (void*)((Name[]){"x", "y"}), EVAR("x")},
	{"S", (void*)((Name[]){"x", "y", "z"}), EAP(EAP(EVAR("x"), EVAR("z")), EAP(EVAR("y"), EVAR("z")))},
	{"B", (void*)((Name[]){"x", "y", "z"}), EAP(EVAR("x"), EAP(EVAR("y"), EVAR("z")))},
	{"C", (void*)((Name[]){"x", "y", "z"}), EAP(EAP(EVAR("x"), EVAR("z")), EVAR("y"))},
	{"W", (void*)((Name[]){"x", "y"}), EAP(EAP(EVAR("x"), EVAR("y")), EVAR("y"))},
};
```
こうじゃ(プリプロセッサ後)

```c
Program preludeDefs = (ScDefn[]){
 {"I", (void*)((Name[]){"x"}), &(Expr){EVar, (void *)(("x")), (void *)(((void *)0))}},
 {"K", (void*)((Name[]){"x", "y"}), &(Expr){EVar, (void *)(("x")), (void *)(((void *)0))}},
 {"S", (void*)((Name[]){"x", "y", "z"}), &(Expr){EAp, (void *)((&(Expr){EAp, (void *)((&(Expr){EVar, (void *)(("x")), (void *)(((void *)0))})), (void *)((&(Expr){EVar, (void *)(("z")), (void *)(((void *)0))}))})), (void *)((&(Expr){EAp, (void *)((&(Expr){EVar, (void *)(("y")), (void *)(((void *)0))})), (void *)((&(Expr){EVar, (void *)(("z")), (void *)(((void *)0))}))}))}},
 {"B", (void*)((Name[]){"x", "y", "z"}), &(Expr){EAp, (void *)((&(Expr){EVar, (void *)(("x")), (void *)(((void *)0))})), (void *)((&(Expr){EAp, (void *)((&(Expr){EVar, (void *)(("y")), (void *)(((void *)0))})), (void *)((&(Expr){EVar, (void *)(("z")), (void *)(((void *)0))}))}))}},
 {"C", (void*)((Name[]){"x", "y", "z"}), &(Expr){EAp, (void *)((&(Expr){EAp, (void *)((&(Expr){EVar, (void *)(("x")), (void *)(((void *)0))})), (void *)((&(Expr){EVar, (void *)(("z")), (void *)(((void *)0))}))})), (void *)((&(Expr){EVar, (void *)(("y")), (void *)(((void *)0))}))}},
 {"W", (void*)((Name[]){"x", "y"}), &(Expr){EAp, (void *)((&(Expr){EAp, (void *)((&(Expr){EVar, (void *)(("x")), (void *)(((void *)0))})), (void *)((&(Expr){EVar, (void *)(("y")), (void *)(((void *)0))}))})), (void *)((&(Expr){EVar, (void *)(("y")), (void *)(((void *)0))}))}},
};
```

(カッコ(多(す)ぎ(ワロタ)))

Mirandaは線形リスト使っているからappendのコストが要素の2乗に比例するとかアホなこと言い出して抽象データ型,_abstract data type_を作り出した.
23ページと24ページの間に

```
M> abstype iseq with
M>       iNil     :: iseq                  || The empty iseq
M>       iStr     :: [char] -> iseq        || Turn a string into an iseq
M>       iAppend  :: iseq -> iseq -> iseq  || Append two iseqs
M>       iNewline :: iseq                  || New line with indentation
M>       iIndent  :: iseq -> iseq          || Indent an iseq
M>       iDisplay :: iseq -> [char]        || Turn an iseq into a string
```

が入る?
iseq型を作ってるけど,実装がわかるまでpprintやその中身を実装できないのが辛い.

```
M1-2> iseqRep ::= INil
M1-2>             | IStr [char]
M1-2>             | IAppend iseqRep iseqRep
```

が正しい1.5.3のすぐ下のソースコードだと思う.
むしろ掲載されているコードは全部GH(glasgow haskell)用?でM(Miranda)用ではない?
よって結構本文中に間違いがある?

**1.5.3まで読んだ.実装は1.4まで.実装の確認はしてない**