Идрис - Невозможно оценить применение функции по типу

Я получаю проблему, когда у меня есть значение с типом fun a, с fun быть функцией и a значение, которое не вычисляется при проверке типов и выдает ошибку объединения, когда я заставляю его быть результатом применения этой функции.

Конкретная ошибка заключается в следующем:

When checking right hand side of testRec2 with expected type
         Record [("A", String), ("C", Nat)]

 Type mismatch between
         Record (projectLeft ["A", "C"]
                             [("A", String),
                              ("B", String),
                              ("C", Nat)]) (Type of hProjectByLabels_comp ["A",
                                                                           "C"]
                                                                          testRec1
                                                                          (getYes (isSet ["A",
                                                                                          "C"])))
 and
         Record [("A", String), ("C", Nat)] (Expected type)

 Specifically:
         Type mismatch between
                 projectLeft ["A", "C"]
                             [("A", String), ("B", String), ("C", Nat)]
         and
                 [("A", String), ("C", Nat)]

Это из реализации HList-подобных записей в Idris со следующим примером:

testRec1 : Record [("A", String), ("B", String), ("C", Nat)]
-- testRec1's value is already defined    

testRec2 : Record [("A", String), ("C", Nat)]
testRec2 = hProjectByLabels_comp ["A", "C"] testRec1 (getYes $ isSet ["A", "C"])

... следующие типы:

IsSet : List t -> Type

isSet : DecEq t => (xs : List t) -> Dec (IsSet xs)

LabelList : Type -> Type

IsLabelSet : LabelList lty -> Type

HList : LabelList lty -> Type

Record : LabelList lty -> Type

recToHList : Record ts -> HList ts

recLblIsSet : Record ts -> IsLabelSet ts

hListToRec : DecEq lty => {ts : LabelList lty} -> {prf : IsLabelSet ts} -> HList ts -> Record ts

IsProjectLeft : DecEq lty => List lty -> LabelList lty -> LabelList lty -> Type

IsProjectRight : DecEq lty => List lty -> LabelList lty -> LabelList lty -> Type

hProjectByLabelsHList : DecEq lty => {ts : LabelList lty} -> (ls : List lty) -> HList ts -> ((ls1 : LabelList lty ** (HList ls1, IsProjectLeft ls ts ls1)), (ls2 : LabelList lty ** (HList ls2, IsProjectRight ls ts ls2)))

projectLeft : DecEq lty => List lty -> LabelList lty -> LabelList lty

hProjectByLabelsLeftIsSet_Lemma2 : DecEq lty => {ls : List lty} -> {ts1, ts2 : LabelList lty} -> IsProjectLeft ls ts1 ts2 -> IsLabelSet ts1 -> IsLabelSet ts2

fromIsProjectLeftToComp : DecEq lty => {ls : List lty} -> {ts1, ts2 : LabelList lty} -> IsProjectLeft ls ts1 ts2 -> IsSet ls -> ts2 = projectLeft ls ts1

hProjectByLabels_comp : DecEq lty => {ts : LabelList lty} -> (ls : List lty) -> Record ts -> IsSet ls -> Record (projectLeft ls ts)

... и следующие (необходимые) определения:

LabelList : Type -> Type
LabelList lty = List (lty, Type)

IsLabelSet : LabelList lty -> Type
IsLabelSet ts = IsSet (map fst ts) 

projectLeft : DecEq lty => List lty -> LabelList lty -> LabelList lty
projectLeft [] ts = []
projectLeft ls [] = []
projectLeft ls ((l,ty) :: ts) with (isElem l ls)
  projectLeft ls ((l,ty) :: ts) | Yes lIsInLs = 
    let delLFromLs = deleteElem ls lIsInLs
        rest = projectLeft delLFromLs ts
    in (l,ty) :: rest
  projectLeft ls ((l,ty) :: ts) | No _ = projectLeft ls ts

deleteElem : (xs : List t) -> Elem x xs -> List t
deleteElem (x :: xs) Here = xs
deleteElem (x :: xs) (There inThere) =
  let rest = deleteElem xs inThere
  in x :: rest 

getYes : (d : Dec p) -> case d of { No _ => (); Yes _ => p}
getYes (No _ ) = ()
getYes (Yes prf) = prf

hProjectByLabels_comp : DecEq lty => {ts : LabelList lty} -> (ls : List lty) -> Record ts -> IsSet ls -> Record (projectLeft ls ts)
hProjectByLabels_comp {ts} ls rec lsIsSet =
  let 
    isLabelSet = recLblIsSet rec
    hs = recToHList rec
    (lsRes ** (hsRes, prjLeftRes)) = fst $ hProjectByLabelsHList ls hs
    isLabelSetRes = hProjectByLabelsLeftIsSet_Lemma2 prjLeftRes isLabelSet
    resIsProjComp = fromIsProjectLeftToComp prjLeftRes lsIsSet
    recRes = hListToRec {prf=isLabelSetRes} hsRes
  in rewrite (sym resIsProjComp) in recRes

В основном, есть функция projectLeft который применяется к 2 спискам и возвращает новый. Тип hProjectByLabels_comp применяет эту функцию на уровне типа. Чтобы на самом деле построить результирующий список, у меня есть предикат стиля Pred l1 l2 l3 и лемма стиля Pred l1 l2 l3 -> l3 = projectLeft l1 l2, В hProjectByLabels_comp Я применяю лемму к предикату и использую rewrite получить правильную подпись типа (переписывание l3, что подразумевается в предикате, который появляется внутри реализации, в projectLeft l1 l2, или же projectLeft ls ts в этом конкретном случае).

Я ожидаю, что применение hProjectByLabels_comp к записи будет вычислять projectLeft ls ts правильно. Тем не менее, в приведенном выше примере не удается оценить / вычислить projectLeft ["A", "C"] [("A", String), ("B", String), ("C", Nat)], Это кажется странным, так как оценка этого приложения функции в REPL дает точно [("A", String), ("C", Nat)]Это то, что ожидает тип, но Idris не может вычислить эту функцию при проверке типа.

Я не уверен, имеет ли какое-то отношение реализация некоторых из лемм / функций, или это только что-то о типах.

Я попытался воспроизвести эту ошибку, используя более простой пример (с предикатами и функциями в Nats), но этот более простой пример проверен на правильность типов, поэтому я не смог найти другой способ воспроизвести эту ошибку.

Я использую Идрис 0.9.20.2

Изменить: я пытался переписать projectLeft следующим образом, чтобы увидеть, если что-то изменилось, но он продолжает показывать ту же ошибку

projectLeft : DecEq lty => List lty -> LabelList lty -> LabelList lty
projectLeft ls [] = []
projectLeft ls ((l,ty) :: ts) with (isElem l ls)
  projectLeft ls ((l,ty) :: ts) | Yes lIsInLs = 
    let delLFromLs = deleteElem ls lIsInLs
        rest = projectLeft delLFromLs ts
    in (l,ty) :: rest
  projectLeft ls ((l,ty) :: ts) | No _ = projectLeft ls ts

2 ответа

Решение

По-видимому, эта проблема теперь решена после обновления до Idris 0.12. Ничего не изменилось, но теперь проверено.

Является projectLeft общая функция? Частичные функции не уменьшают сигнатуры типов, то есть вы просто видите, что они применяются к своим аргументам, а не к тому, к чему сводится результат этого приложения.

Пример, демонстрирующий это:

type : Int -> Type
type 0 = String

a : type 0
a = "Hello"

не удастся скомпилировать с ошибкой типа с жалобой на невозможность сопоставления type 0 с String, Несмотря на функцию type будучи определенным для рассматриваемого значения, Идрис отказывается применять частичные функции в сигнатурах типов. Вы все еще можете применить его в ответе, хотя. type 0 дает String : Type, а также type 1 дает type 1 : Type (Нередуцированный).

Другие вопросы по тегам