F#中的扩展功能

问题描述 投票:0回答:1

在下面的代码中,executeProg函数正在执行程序指令列表。它使用“ PUSH ax,POP bx ..etc”执行程序。


//Execute a program as a list of operations. Note how pc is incremented
//so any jump instruction must be written carefully.
let mutable executeProg = fun (program:operation list) ->
  pc <- 0
  fault <- false
  while not(fault) && pc<program.Length do
    let instruction = program.[pc];
    execute instruction
    pc <- pc+1
  // end of while by indentation
  if not(fault) then printfn "top of stack holds value %d" (RAM.[sp-1]);

我想做的是:修改executeProg使其执行以下操作:

push ax
pop bx      --> replace with single instruction mov ax bx 

push ax
pop ax      --> eliminate altogether

mov ax bx
mov bx ax   -->   mov ax bx

我的问题是,如何在不更改原始模型的情况下实现新的executeProg模态?我的代码如下:

let base_executeProg = executeProg

executeProg <- fun program (program:operation list) ->

let rec matchingFun = fun newProgram (program:operation list ) ->
let mutable newProgram = newProgram

    match program with 
    | (PUSH(Reg(a)):: POP(Reg(b)) :: r) -> 
        newProgram <- newProgram @ [MOV(Reg(a),Reg(b))]
        (matchingFun (newProgram r))
        newProgram
    | (PUSH(Reg(a)):: POP(Reg(a))::r) ->
        (matchingFun (newProgram r))
        newProgram
    | (MOV(Reg(a),Reg(b)):: MOV(Reg(b),Reg(a)):: r) ->
        newProgram <- newProgram @ [MOV(Reg(a),Reg(b))]
        (matchingFun (newProgram r))
        newProgram
    | (a::r) -> 
        newProgram <- newProgram @ [a]
        matchingFun(newProgram,r)
        newProgram
    | [] -> newProgram

我是F#语言的新手,我想知道我的语法是否正确。感谢您的帮助谢谢。

f#
1个回答
0
投票

我认为您不需要具有可变功能。也许您可以将设计更改为使用不变的,可组合的结构,从而使您可以向解决方案中添加新功能。

我有点打问题了,这就是我得到的。

声明将在程序中使用的类型:

type Register = 
    | AX 
    | BX

type Operand =
    | Register of Register
    | Int of int


type Command = 
| MOV of Register * Operand
| PUSH of Operand
| POP of Operand

type FnBinaryOp = Register -> Operand -> Command
type FnUnaryOp = Operand -> Command

type Program = Command list

//two helper functions to save some typing
let i n = Int n
let r n = Register n

//helper functions to clarify the declaration syntax
let mov:FnBinaryOp = 
    fun reg op -> MOV (reg, op)

let push: FnUnaryOp = fun op -> PUSH (op)

let pop: FnUnaryOp = fun op -> POP (op)

实施优化方法-它返回修改后的指令列表。这是纠正代码效率低下的地方。

///optimize the program - remove cancelling stack commands, simplify MOV commands
let optimize (program:Program) = 
   let rec recOptimize stack prog = 
       match prog with
       | PUSH (Register r1)::POP (Register r2)::xs when r1 = r2 -> //push ax; pop ax => nop
           xs |> recOptimize stack
       | PUSH (Register r1)::POP (Register r2)::xs when r1 <> r2 -> //push ax; pop bx => move ax bx
           xs |> recOptimize (MOV(r1, Register(r2))::stack)
       | PUSH (Int i1)::POP (Int i2)::xs when i1 = i2 -> //push 3; pop 3 => nop
           xs |> recOptimize stack
       | ((MOV (r1, Register r2 )) as op1)::((MOV (r3, Register r4 )) as op2)::xs when r1 = r4 && r2 = r3 -> //move ax bx; move bx ax => move ax bx
           xs |> recOptimize (op1::stack)
       | ((MOV (r1, Register r2 )) as op1)::((MOV (r3, Register r4 )) as op2)::xs when r1 = r3 && r2 = r4 -> //move ax bx; move ax bx => move ax bx
           xs |> recOptimize (op1::stack)
       | op::xs -> //all other cases - pass through
           xs |> recOptimize (op::stack)
       | [] -> stack

   program 
   |> recOptimize []

实现程序的实际执行(此处未实现)

let runProgram (program:Program) = 
    let rec run stack prog =
        []
    program |> run []

这是调用此方法的方法:

let program:Program = [
    mov AX (r BX)
    push (r BX)
    pop (r BX)
    mov AX (r BX)
    ]

program 
|> optimize 
|> runProgram

如果需要在优化步骤中添加新功能,则只需替换复合调用中的optimize元素即可。您可以运行多次遍历的优化,以涵盖某些操作“成对”并且您也要对其进行优化的情况。程序|>优化|>优化|> runProgram

以下是一些测试:

[<Fact>]
let ``push 42; pop 42 => nop`` () =
    let program:Program = [
        push (i 42)
        pop (i 42)
        ]
    let optimized = program |> optimize

    //should be reduced to empty list
    Assert.Empty(optimized)

[<Fact>]
let ``push ax; pop ax => nop`` () =
    let program:Program = [
        push (r AX)
        pop (r AX)
        ]
    let optimized = program |> optimize

    //should be reduced to empty list
    Assert.Empty(optimized)

[<Fact>]
let ``push ax; pop bx => move ax bx`` () =
    let program:Program = [
        push (r AX)
        pop (r BX)
        ]
    let optimized = program |> optimize

    //should be reduced to a single element list mov ax bx
    let expected = MOV( AX, (r BX))
    let op = optimized.Head
    Assert.Equal(1, optimized.Length)
    Assert.Equal(expected, op)

[<Fact>]
let ``move ax bx; move bx ax => move ax bx`` () =
    let program:Program = [
        mov AX (r BX)
        mov BX (r AX)
        ]
    let optimized = program |> optimize

    //should be reduced to a single element list mov ax bx
    let expected = MOV( AX, (r BX))
    let op = optimized.Head
    Assert.Equal(1, optimized.Length)
    Assert.Equal(expected, op)

[<Fact>]
let ``run optimize on program`` () =
    let program:Program = [
        mov AX (r BX)
        push (r BX)
        pop (r BX)
        mov AX (r BX)
        ]
    let optimized = program 
                    |> optimize
                    |> optimize
                    |> optimize

    //should be reduced to a single element list mov ax bx
    let expected = MOV( AX, (r BX))
    let op = optimized.Head
    Assert.Equal(1, optimized.Length)
    Assert.Equal(expected, op)
© www.soinside.com 2019 - 2024. All rights reserved.