2016-05-19 59 views
3

我正在嘗試創建一個函子,它使一個多項式環出環。我的基本類型,Ring_elt,具有以下特徵:函數中的OCaml語法錯誤

module type Ring_elt = sig 
    type t 
    val add : t -> t -> t 
    val mul : t -> t -> t 
    val zer : t 
    val one : t 
    val neg : t -> t 
end;; 

我的多項式函數對象的樣子:

module Make_Poly2(Underlying:Ring_elt) = struct 
    type t = Poly of Underlying.t list 
    let rec create lst = 
    match List.rev lst with 
    | Underlying.zer :: tl -> create List.rev tl 
    | _     -> Poly of lst 
end;; 

(使「創建」功能應該採取列表,刪除前導零,然後返回結果的多項式)。但是,我收到語法錯誤,並且utop強調了「底層」之後的「zer」。

相比之下,下面的代碼(用於製作整數多項式)工作原理:

module Make_int_poly = struct 
    type t = Poly of int list 
    let rec create lst = 
    match List.rev lst with 
    | 0 :: tl -> create (List.rev tl) 
    | _  -> Poly lst 
end;; 

任何想法是怎麼回事?

+1

你應該編輯第一個代碼,因爲你有一個語法錯誤'Poly of lst'和一個輸入錯誤'create List.rev tl'(這些都在你的第二個例子中都被修正了)。 – Lhooq

+0

謝謝。對於與其他語法錯誤一起快速而寬鬆地抱歉。 –

+0

看起來,調用'match List.rev lst with ... :: tl - > ... List.rev tl'是獲取列表最後一個元素的低效方法(因爲您幾乎要重建整個列表兩次)。相反,做一個函數'last:'列表 - >'一個選項'。爲了消除前導零(就像列表中的第一個零),你可能會喜歡一個函數'dropWhile:('a - > bool) - >'列表 - >'列表' https://hackage.haskell.org/package/base-4.8.2.0/docs/Data-List.html#v:dropWhile)。 –

回答

1

傑弗裏的答案是好的,但不是與if建設修正它,你應該做的是:使用代數數據類型

而不是寫

val zer : t 
val one : t 

你可以寫

module type Ring_elt = sig 
    type t = Zer | One | Num of t 
    val add : t -> t -> t 
    val mul : t -> t -> t 
    val neg : t -> t 
end 

module Make_int_poly = struct 
    type t = Poly of int list 
    let rec create lst = 
    match List.rev lst with 
    | Underlying.Zer :: tl -> create (List.rev tl) 
    | _     -> Poly lst 
end 

這是一個更好的方法,因爲你可以很容易地模式匹配它,甚至添加一些常數到您的類型t沒有問題。

+0

感謝您的回答。關於常量和代數數據類型的一個簡單問題:一旦我添加常量Zer和One,是否有強制平等的方法,例如,如果我的基礎類型是具有標準結構的整數,我如何強制編譯器看'int 0'並看到'Zer'? –

+0

這個特殊的代數類型似乎有點模棱兩可,因爲'Num Zero'和'One'似乎是用不同的方式表示的,例如'Num(Num Zero)'和'Num One'等等。考慮有一個模式構造函數爲0和1的便利性與數字的有效表示。也就是說,你也可以把'val is_zer:t - > bool'作爲你的簽名的一部分,並增加了抽象的好處。 –

+0

@SimonShine那麼,你可以將't'類型定義爲私有的(在一個簽名中),然後只能用適當的函數創建一個't'類型的值。因此,例如,創建'Num(Num Zero)'是不可能的。 'Num Zero'和'One'不一樣,是嗎?我的意思是,一個是0,另一個是1. :-D – Lhooq

2

OCaml模式由常量,數據構造函數和模式匹配所綁定的新名稱構建而成。 Underlying.zer不是這些東西中的任何一個。但0就是其中之一。

似乎你可以使用if來比較Underlying.zer

+0

是的,所以'Underlying.zer'是一個有效的值構造函數,但它不是一個有效的模式構造函數,與'0'不同。 –

+0

Jeremy Scofield和@Simon Shine,謝謝你的回答和評論;這些正是我希望習慣的ocaml的怪癖。我接受Lhooq的回答,但所有答案都是好的。 –

+0

@JohnBinder:好的。我從來沒有想過模式構造函數是古怪的,但承認當我最初瞭解代數數據類型定義不僅創建了值構造函數,而且還爲值析構函數(模式構造函數)賦值時,以及內置的值文字配音作爲兩者,這是令人驚訝的。它確實必須是這樣的,即只有在編譯時已知的值才能用作模式,以將模式匹配的成本保持在可預測的低水平。 (如果運行時生成的值是有效模式,那麼使用'='執行結構相等性的成本可能會不可預測。) –