Previous Up Next

3.5牋ML3 — 簇眶の瞥掐

ここまでのところ·この咐胳には·いくつかのプリミティブ簇眶(企灌遍换灰) しか捏丁されておらず·MLプログラマが(プリミティブを寥み圭わ せて)糠しい簇眶を年盗することはできなかったˉML3 では·fun及 による簇眶藐据と·簇眶努脱を捏丁するˉ

3.5.1牋簇眶及と努脱及

まずは·ML3 の及の矢恕を绩すˉ

<及>::=…�
 |fun�<急侍灰>�→�<及>�
 |<及1>�<及2>

菇矢に簇するインタプリタˇプログラムは·哭8に绩すˉ 努脱及は焊冯圭で·戮の链ての遍换灰よりも冯圭が动いとするˉ


syntax.ml:

type exp = 
   ...
  | FunExp of id * exp
  | AppExp of exp * exp

parser.mly:

%token RARROW FUN

Expr :
   ...
   | FunExpr { $1 }

MExpr :
    MExpr MULT AppExpr { BinOp (Mult, $1, $3) }
  | AppExpr { $1 }

AppExpr :
    AppExpr AExpr { AppExp ($1, $2) }
  | AExpr { $1 }

lexer.mll:

let reservedWords = [
   ...
  ("fun", Parser.FUN);
   ...
]
...
| "=" { Parser.EQ }
| "->" { Parser.RARROW }

Figure 8: 簇眶と努脱(1)


3.5.2牋簇眶誓蜀と努脱及の删擦

さて·Objective Camlと票屯·ML3 においても·簇眶は及を删擦した冯蔡とな るだけでなく·恃眶の芦躯滦据にもなる妈办甸の猛(first-class value)として胺うˉそのため·expressed value, denoted value ともに 簇眶猛を裁えて橙磨するˉ

Expressed Value=腊眶�(…,�−2,�−1,�0,�1,�2,�3,�…)�+牽康睹蜖+ 簇眶猛�
Denoted Value=Expressed Value

さて·簇眶猛をどのように山附するかを雇えるˉfun 及が努脱された箕には·パラメ〖タを悸苞眶(の猛)に芦躯し·簇眶塑挛を删擦 するので·警なくともパラメ〖タの叹涟と·塑挛の及の攫鼠が涩妥であるˉしかし· 办忍弄には·笆布の毋のように·簇眶塑挛の及にパラメ〖タ笆嘲の恃眶(つま り极统恃眶)が叫附することも材墙であるˉ


let x = 2 in
let addx = fun y → x + y in
addx 4

x の琅弄芦躯を悸附するためには·この addx の努脱を乖う狠には 塑挛面の x が 2 であることを淡峡しておかなければならないˉ というわけで·办忍弄に簇眶が努脱される箕には·

  1. パラメ〖タ叹
  2. 簇眶塑挛の及·に裁え
  3. 塑挛面のパラメ〖タで芦躯されていない恃眶(极统恃眶)の芦躯攫鼠 (叹涟と猛)

が涩妥になるˉこの3つを寥にしたデ〖タを簇眶誓蜀ˇクロ〖ジャ(function closure) と钙び·これを簇眶猛として脱いるˉここで侯喇するインタプリ タでは·塑挛面の极统恃眶の芦躯攫鼠として·fun及が删擦された箕爬 での茨董链挛を蝗脱するˉこれは·塑挛面に附れない恃眶に簇する途纷な芦躯 攫鼠を崔んでいるが·もっとも帽姐な簇眶誓蜀の悸附数恕であるˉ

笆惧を僻まえた eval.ml への肩な恃构爬は哭9のようになるˉ 及の猛には·茨董を崔むデ〖タである簇眶誓蜀が崔まれるため·exval と dnval の年盗が(陵高)浩耽弄になるˉ簇眶 猛は ProcV コンストラクタで山され·惧で揭べたように·パラメ〖タ叹の リスト·塑挛の及と茨董の寥を瘦积するˉeval_exp で FunExp を借妄す る箕には·その箕爬での茨董·つまりenv を蝗って簇眶誓蜀を侯っているˉ 努脱及の借妄は·努脱される簇眶の删擦·悸苞眶の删擦を乖った稿·塑碰に努 脱されている及が簇眶かどうかのチェックをして·塑挛の删擦を乖っているˉ 塑挛の删擦を乖う狠の茨董 newenv は·簇眶誓蜀に呈羌されている茨董を·パ ラメ〖タˇ悸苞眶で橙磨して评ているˉ


eval.ml:

type exval =
    IntV of int
  | BoolV of bool
  | ProcV of id * exp * dnval Environment.t
and dnval = exval

let rec eval_exp env = function
   ...
  | FunExp (id, exp) -> ProcV (id, exp, env)
  | AppExp (exp1, exp2) ->
      let funval = eval_exp env exp1 in
      let arg = eval_exp env exp2 in
       (match funval with
            ProcV (id, body, env') ->
              let newenv = Environment.extend id arg env' in
                eval_exp newenv body
          | _ -> err ("Non-function value is applied"))

Figure 9: 簇眶と努脱(3)


Exercise�8牋[涩饯草玛] ML3 インタプリタを侯喇し·光超簇眶が赖しく瓢侯するかなどを崔めて テストせよˉ
Exercise�9牋[岂白刨 2] Objective Caml での≈(面弥遍换灰) ∽淡恕をサポ〖トし·プリミティブ遍换 を奶撅の簇眶と票屯に胺えるようにせよˉ毋えば

let threetimes = fun f → fun x → f (f x x) (f x x) in
  threetimes (+) 5
は·20を叫蜗するˉ
Exercise�10牋[岂白刨 1] Objective Caml の
fun x1 ... xn → ...
let f x1 ... xn = ...
といった词维淡恕をサポ〖トせよˉ
Exercise�11牋[岂白刨 1] 笆布は·裁换を帆り手して 4 による齿け换を悸附している ML3 プログラムであるˉこれを猖陇して·超捐を纷换するプログラムを 今けˉ

let makemult = fun maker → fun x →
                 if x < 1 then 0 else 4 + maker maker (x + -1) in
let times4 = fun x → makemult makemult x in
  times4 3
Exercise�12牋[岂白刨 1] 琅弄芦躯とは滦救弄な车前として瓢弄芦躯(dynamic binding)があ るˉ瓢弄芦躯の布では·簇眶塑挛は·fun及を删擦した箕爬ではなく· 簇眶钙び叫しがあった箕爬での茨董をパラメ〖タˇ悸苞眶で橙磨した茨董布 で删擦されるˉ毋えば·

let a = 3 in
let p = fun x → x + a in
let a = 5 in
  a * p 2
というプログラムで·簇眶p塑挛面の a は 3 ではなく 5 に芦躯されるˉインタプリタを猖陇し·瓢弄芦躯を 悸附せよˉ
Exercise�13牋[岂白刨 1] 瓢弄芦躯の布では·ML4 で瞥掐するような浩耽年盗を悸附するための泼侍な慌寥みや·Exercise�11のようなトリックを蝗うことなく· 浩耽簇眶を年盗できるˉ笆布のプログラムを琅弄芦躯ˇ瓢弄芦躯の布で 悸乖し·冯蔡について棱汤せよˉ

let fact = fun n → n + 1 in
let fact = fun n → if n < 1 then 1 else n * fact (n + -1) in
  fact 5

Previous Up Next