讓它編譯
那麼,你是TA是錯的,那個代碼片段不能編譯。這裏有一個編譯版本:
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格式化代碼。我發現你的代碼之前,以下問題編譯:
polyX
使用不合格map
功能,但目前還沒有進口,所以你應該使用合格List.map
。
- 類型
RegisterNumber
和RegisterValue
是類型別名。使用type alias
這些,否則你定義構造Int
和Float
爲完全獨立的類型RegisterNumber
和RegisterValue
,而不是與那些在類型Int and
Float`。
Const
分支e2C
沒有返回列表,但case
的其他分支是。
Mult
分支e2C
正在使用Mult
而不是Multiply
作爲結果,它是Expr
而不是Instr
。
得到它的工作
免責聲明:檢查你詐騙學校/課程規定。根據我的經驗,學生只能提交自己寫的解決方案。關於解決方案的高層討論通常是可以的,複製代碼很可能不會。根據學校的欺詐規定,這個答案可能會過於詳細。引用您的來源並不總是足夠的!
給出你可以做的三條指令,將結果從一個寄存器移到另一個寄存器並不容易。這將需要僞造指令,如[LoadImmediate freeRegister 0, Addition moveToThisRegister MoveFromThisRegister freeRegister]
。所以你不能優雅地創建一個精細的編譯器,而且你可能不需要,因爲你只被要求完成幫助函數e2C
。
因此,我們正在尋找簡單,非一般的解決方案。您需要對獲取的Expr
進行一些假設。請注意,polyX
僅生成左側不確定的加法和乘法運算(Const
或Var
)。這是我們將利用的財產。
因此,如果您先執行右側表達式,然後爲該表達式賦予相同的結果寄存器,那麼您的左側仍有兩個空閒寄存器(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的寄存器。
非常感謝您的幫助!但對於Var _ - >的情況,我從來沒有學過這個。 Var _ - > []是否有效? – Eliscpe
@Eliscpe當然,你可以返回一個空的列表。這意味着當你的程序碰到一個不是x的變量時,它會輸出垃圾指令。不是我在真正的軟件中推薦的東西,但是如果這是您對作業的期望,那就去做吧。 – Apanatshka
我被告知Var「x」是錯誤的,因爲我已經告訴x的值已經在寄存器2中了。我該如何解決這個問題? – Eliscpe