2013-07-28 5 views
14

Я пытаюсь перевести на Идрис пример из Cayenne - язык с зависимыми типамиpaper.Впечатано в печатном виде в Idris

Вот то, что я до сих пор:

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])) 

Я использую List Char вместо String для формата аргумента для того, чтобы облегчить с сопоставлением с образцом, как я быстро побежал в сложности с соответствующим узором на 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-х элементов (те, с '%' :: ...) в PrintfType и printf, то код компилируется (но, очевидно, ничего интересного не делает).

Как исправить мой код, чтобы 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 является символьным символом. Использование Format Я могу определить PrintfType и реализовать printFormat. Оттуда я могу плавно перейти к возьмите строку, а не List Char или значение Format. И конечный результат:

*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, где говорится: «Верните доказательство того, что целое число находится в требуемом диапазоне вместе с самим целым» , Поэтому, я думаю, вам придется разбирать строку формата и возвращать ее с помощью доказательства, которое имеет некоторый формат. – huynhjl

 Смежные вопросы

  • Нет связанных вопросов^_^