Elm 语言编码错误

Elm Language Coding Error

type Expr = Const Float | Var String| Add Expr Expr| Mult Expr Expr

list = [3,1,4]

polyX : List Float -> Expr
polyX coeffs = polyHelper <| map Const <| coeffs
polyHelper: List Expr -> Expr
polyHelper e = case e of
     [x] -> x
     (x::xs) -> Add x(Mult(Var "x")(polyHelper xs))
     [] -> Const 1

type Instr = LoadImmediate RegisterNumber --put value here
                           RegisterValue  --the value

           | Addition      RegisterNumber --put result here
                           RegisterNumber --first thing to add
                           RegisterNumber --first thing to multiply

           | Multiply      RegisterNumber --put result here
                           RegisterNumber --first thing to multiply
                           RegisterNumber --second thing to multiply

type RegisterNumber = Int
type RegisterValue = Float

expr2Code : Expr -> List Instr
expr2Code expr = e2C 1 expr

e2C result expr = case expr of
                 Const x -> ((LoadImmediate(result+2))x)
                 Add expr1 expr2 -> (Addition result result (result+1))::(e2C result expr2)++(e2C result expr1)
                 Mult expr1 expr2 -> (Mult result result(result+1))::(e2C result expr2)++(e2C result expr1)
                 Var x -> []

我的作业有困难。

问题:

Assume that the only variable you will see is x and it is already in register 2. Arrange for the result to arrive to be in register 1 at the end of the computation, and use registers 3 and 4 for other values, as needed. Write the helper function e2C to complete.

我的T.A说我现在的代码可以编译,但不能解决问题。

谁能告诉我如何修改代码以解决问题?

正在编译

好吧,你错了,该代码片段无法编译。这是一个编译版本:

type Expr
  = Const Float
  | Var String
  | Add Expr Expr
  | Mult Expr Expr

type Instr
  = LoadImmediate RegisterNumber --put value here
                  RegisterValue  --the value
  | Addition      RegisterNumber --put result here
                  RegisterNumber --first thing to add
                  RegisterNumber --first thing to multiply
  | Multiply      RegisterNumber --put result here
                  RegisterNumber --first thing to multiply
                  RegisterNumber --second thing to multiply

type alias RegisterNumber
  = Int

type alias RegisterValue
  = Float

list : List Float
list =
  [3,1,4]

polyX : List Float -> Expr
polyX coeffs =
  polyHelper <| List.map Const <| coeffs

polyHelper: List Expr -> Expr
polyHelper e =
  case e of
    [x] ->
      x

    (x::xs) ->
      Add x (Mult (Var "x") (polyHelper xs))

    [] ->
      Const 1

expr2Code : Expr -> List Instr
expr2Code expr =
  e2C 1 expr

e2C : RegisterNumber -> Expr -> List Instr
e2C result expr =
  case expr of
    Const x ->
      [LoadImmediate (result+2) x]

    Add expr1 expr2 ->
      Addition result result (result+1)
      :: e2C result expr2 ++ e2C result expr1

    Mult expr1 expr2 ->
      Multiply result result (result+1)
      :: e2C result expr2 ++ e2C result expr1

    Var x ->
      []

我已经根据 style guide 对代码进行了格式化。我在编译你的代码之前发现了以下问题:

  1. polyX 使用了一个不合格的 map 函数,但是没有导入,所以你应该使用合格的 List.map
  2. 类型RegisterNumberRegisterValue是类型别名。对那些使用 type alias,否则你要为完全独立的类型 RegisterNumber 和 [=16= 定义 构造函数 IntFloat ] 而不是将它们与 types Int andFloat` 相关联。
  3. e2C 中的 Const 分支没有返回列表,但 case 的其他分支是。
  4. e2C 中的 Mult 分支使用 Mult 而不是 Multiply 作为结果,它是 Expr,而不是 Instr.

开始工作

免责声明: 查看您的 school/course 欺诈法规。根据我的经验,学生应该只提交他们自己编写的解决方案。关于解决方案的高层讨论通常是可以的,复制代码很可能是不行的。根据您学校的欺诈规定,此答案可能过于详细。引用您的消息来源并不总是足够的!

考虑到您可以执行的三个指令,将结果从一个寄存器移动到另一个寄存器并不容易。这将需要像 [LoadImmediate freeRegister 0, Addition moveToThisRegister MoveFromThisRegister freeRegister] 这样的虚假指令。所以你不能优雅地创建一个精心设计的编译器,而且你可能不必这样做,因为你只被要求完成辅助函数 e2C

因此,我们将寻求简单、非通用的解决方案。您需要对输入的 Expr 做出一些假设。请注意,polyX 仅生成具有某种常数(ConstVar)的加法和乘法左手边。这是我们要利用的 属性。

因此,如果您首先执行右侧表达式,并为该表达式提供与您提供的相同的结果寄存器,那么您的左侧仍然有两个空闲寄存器(3 和 4)。始终只使用其中一个,然后在结果寄存器和选择的空闲寄存器之间进行操作。

在没有移动操作的情况下,将变量 x 的值移动到不同的寄存器有点难看。但它相当通用,所以让我们使用剩余的空闲寄存器将 0 添加到变量 x 的值并将该值保存到我们应该将结果放入的寄存器中。这为您提供了以下实现:

registerOfX : RegisterNumber
registerOfX = 2

freeRegister1 : RegisterNumber
freeRegister1 = 3

freeRegister2 : RegisterNumber
freeRegister2 = 4

e2C : RegisterNumber -> Expr -> List Instr
e2C resultRegister expr =
  case expr of
    Const value ->
      [LoadImmediate resultRegister value]

    Add expr1 expr2 ->
      e2C resultRegister expr2
      ++ e2C freeRegister1 expr1
      ++ [Addition resultRegister freeRegister1 resultRegister]

    Mult expr1 expr2 ->
      e2C resultRegister expr2
      ++ e2C freeRegister1 expr1
      ++ [Multiply resultRegister freeRegister1 resultRegister]

    Var "x" ->
      [LoadImmediate freeRegister2 0, Addition resultRegister registerOfX freeRegister2]

    Var _ ->
      "Cannot handle "
      ++ toString expr
      ++ ", we only know of "
      ++ toString (Var "x")
      |> Debug.crash

最后一点,因为这已经是一个很长的答案了。您会看到此代码会产生一些冗余的 LoadImmediate 4 0 指令。您可以通过执行 LoadImmediate freeRegister2 0 :: case expr of ... 之类的操作将它的信号指令添加到列表的前面。然后您可以在一条指令中将变量 x 移动到寄存器。指令的任何进一步最小化都需要额外的步骤,这些步骤最好在进一步的辅助函数中完成,或者您需要通过直接匹配 Mult (Var "x") expr2 并直接使用变量 x 的寄存器来降低代码的通用性。