std: 표준 라이브러리 — effect 다형성이 처음으로 검사된다
std/list.cool, string.cool, int.cool, bool.cool. 본문 없는 선언이고 런타임이 구현한다. 이 파일들은 구현이 아니라 시험대다. 부채 상환이 아니라 검증이다. std가 없을 때 List.each는 모르는 이름이라 조용히 통과했다. "모르는 것을 틀렸다고 말하지 않는다"는 맞는 원칙이지만, 그 그늘에 검사되지 않는 영역이 숨어 있었다. 넣자마자 샘플 01이 깨졌다 — List.each에 Result를 반환하는 클로저를 넘기고 그 안에서 ?를 쓰고 있었다. each는 값을 남기지 않는 클로저만 받고, ?는 클로저 밖으로 나가지 못하며, 결과를 버릴 방법은 언어에 없다. map으로 고쳤다. 이것이 std를 먼저 한 이유 그 자체다. - IR은 이제 모듈 그래프 전체를 받고 전역 이름은 "<경로>#<이름>"으로 정규화된다. 별칭은 가져오는 쪽의 선택이므로 실행 의미에 남아서는 안 된다. - 본문 없는 선언은 런타임 구현으로 낮아지고, 그 이름은 모듈 파일에서 온다 (std/list.cool의 each = "list.each"). 별칭과 무관하다. - prelude 없음. std도 명시적으로 가져온다. - samples/12: effect 변수가 호출 지점에서 실제로 해소된다는 증거. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019ZVDeU6KLuUVL3gs18Hm3E
This commit is contained in:
+14
-12
@@ -104,11 +104,12 @@ let root_capability name : value option =
|
||||
|
||||
let builtin pos name (args : value list) : value =
|
||||
match (name, args) with
|
||||
| "String.concat", [ VStr a; VStr b ] -> VStr (a ^ b)
|
||||
| "String.len", [ VStr a ] -> VInt (String.length a)
|
||||
| "Int.show", [ VInt n ] -> VStr (string_of_int n)
|
||||
| "Bool.show", [ VBool b ] -> VStr (if b then "true" else "false")
|
||||
| "List.len", [ VList xs ] -> VInt (List.length xs)
|
||||
| "string.concat", [ VStr a; VStr b ] -> VStr (a ^ b)
|
||||
| "string.len", [ VStr a ] -> VInt (String.length a)
|
||||
| "int.show", [ VInt n ] -> VStr (string_of_int n)
|
||||
| "int.abs", [ VInt n ] -> VInt (abs n)
|
||||
| "bool.show", [ VBool b ] -> VStr (if b then "true" else "false")
|
||||
| "list.len", [ VList xs ] -> VInt (List.length xs)
|
||||
| _ ->
|
||||
fail pos (Printf.sprintf "%s은(는) 런타임이 제공하지 않습니다 (표준 라이브러리가 아직 없습니다)" name)
|
||||
|
||||
@@ -217,16 +218,16 @@ and apply st pos f args =
|
||||
try eval st env body with Return_exc v -> v)
|
||||
| VCtor (enum, name, _) -> VEnum (enum, name, args)
|
||||
(* 고차 builtin은 여기서 처리한다 — apply를 다시 부를 수 있어야 하므로 *)
|
||||
| VBuiltin "List.each" -> (
|
||||
| VBuiltin "list.each" -> (
|
||||
match args with
|
||||
| [ VList xs; f ] ->
|
||||
List.iter (fun x -> ignore (apply st pos f [ x ])) xs;
|
||||
VUnit
|
||||
| _ -> fail pos "List.each는 리스트와 함수를 받습니다")
|
||||
| VBuiltin "List.map" -> (
|
||||
| _ -> fail pos "list.each는 리스트와 함수를 받습니다")
|
||||
| VBuiltin "list.map" -> (
|
||||
match args with
|
||||
| [ VList xs; f ] -> VList (List.map (fun x -> apply st pos f [ x ]) xs)
|
||||
| _ -> fail pos "List.map은 리스트와 함수를 받습니다")
|
||||
| _ -> fail pos "list.map은 리스트와 함수를 받습니다")
|
||||
| VBuiltin n -> builtin pos n args
|
||||
| VNative f -> f args
|
||||
| other -> fail pos (Printf.sprintf "%s은(는) 부를 수 없습니다" (show other))
|
||||
@@ -312,11 +313,12 @@ and eval_binary st env op a b pos =
|
||||
|
||||
(* main이 선언한 capability만 런타임이 넘긴다. 선언하지 않은 권한은
|
||||
프로그램 안에 존재하지 않는다. *)
|
||||
let run (prog : Ir.program) (main_params : (string * string) list) :
|
||||
(string, Token.pos * string) result =
|
||||
let run (prog : Ir.program) (entry : string)
|
||||
(main_params : (string * string) list) : (string, Token.pos * string) result
|
||||
=
|
||||
Buffer.clear out;
|
||||
let st = { prog } in
|
||||
match Hashtbl.find_opt prog.Ir.fns "main" with
|
||||
match Hashtbl.find_opt prog.Ir.fns (entry ^ "#main") with
|
||||
| None -> Error (Token.{ line = 0; col = 0 }, "main 함수가 없습니다")
|
||||
| Some fn -> (
|
||||
let args =
|
||||
|
||||
Reference in New Issue
Block a user