2013-07-28 40 views
14

我想翻譯伊德里斯從Cayenne的例子 - 一種依賴類型的語言paper在伊德里斯依賴打印printf

這是我到目前爲止有:

PrintfType : (List Char) -> Type 
PrintfType Nil    = String 
PrintfType ('%' :: 'd' :: cs) = Int -> PrintfType cs 
PrintfType ('%' :: 's' :: cs) = String -> PrintfType cs 
PrintfType ('%' :: _ :: cs) = PrintfType cs 
PrintfType (_ :: cs)  = PrintfType cs 

printf : (fmt: List Char) -> PrintfType fmt 
printf fmt = rec fmt "" where 
    rec : (f: List Char) -> String -> PrintfType f 
    rec Nil acc = acc 
    rec ('%' :: 'd' :: cs) acc = \i => rec cs (acC++ (show i)) 
    rec ('%' :: 's' :: cs) acc = \s => rec cs (acC++ s) 
    rec ('%' :: _ :: cs) acc = rec cs acc -- this is line 49 
    rec (c :: cs)  acc = rec cs (acC++ (pack [c])) 

爲了便於與模式匹配爲我趕緊跑進複雜性與String模式匹配,我使用List Char代替String格式說法。

不幸的是我得到一個錯誤信息,我無法弄懂:

Type checking ./sprintf.idr 
sprintf.idr:49:Can't unify PrintfType (Prelude.List.:: '%' (Prelude.List.:: t cs)) with PrintfType cs 

Specifically: 
    Can't convert PrintfType (Prelude.List.:: '%' (Prelude.List.:: t cs)) with PrintfType cs 

如果我註釋掉所有的模式匹配的情況下與3個元素(那些與'%' :: ...)在PrintfTypeprintf,然後代碼編譯(但顯然沒有做任何有趣的事情)。

如何修復我的代碼以便printf "the %s is %d" "answer" 42有效? 。

回答

13

它看起來像定義,其中圖案重疊功能,當有伊德里斯一些current limitations(例如'%' :: 'd'c :: cs重疊多次嘗試後,我終於想出了一個解決方法是:

data Format = End | FInt Format | FString Format | FChar Char Format 
fromList : List Char -> Format 
fromList Nil    = End 
fromList ('%' :: 'd' :: cs) = FInt (fromList cs) 
fromList ('%' :: 's' :: cs) = FString (fromList cs) 
fromList (c :: cs)   = FChar c (fromList cs) 

PrintfType : Format -> Type 
PrintfType End   = String 
PrintfType (FInt rest) = Int -> PrintfType rest 
PrintfType (FString rest) = String -> PrintfType rest 
PrintfType (FChar c rest) = PrintfType rest 

printf : (fmt: String) -> PrintfType (fromList $ unpack fmt) 
printf fmt = printFormat (fromList $ unpack fmt) where 
    printFormat : (fmt: Format) -> PrintfType fmt 
    printFormat fmt = rec fmt "" where 
    rec : (f: Format) -> String -> PrintfType f 
    rec End acc   = acc 
    rec (FInt rest) acc = \i: Int => rec rest (acC++ (show i)) 
    rec (FString rest) acc = \s: String => rec rest (acC++ s) 
    rec (FChar c rest) acc = rec rest (acC++ (pack [c])) 

Format是一個表示格式字符串的遞歸數據類型FInt是一個int佔位符,FString是一個字符串佔位符,FChar是一個char字符,使用Format我可以定義PrintfType並執行​​。取一個字符串而不是List CharFormat的值。最終的結果是:

*sprintf> printf "the %s is %d" "answer" 42 
"the answer is 42" : String 
+1

需要提供什麼樣的證明才能使此printf使用運行時字符串? – is7s

+0

@ is7s,好問題,我不知道。自從這個問題/答案以來我沒有和伊德里斯玩過。我可以在http://eb.host.cs.st-andrews.ac.uk/drafts/eff-tutorial.pdf中看到一些想法,它表示_return證明整數與整數本身一起在所需的範圍內_ 。所以我想你將不得不解析格式字符串,並返回一個有格式的證明。 – huynhjl