问题
Type-Driven Development with Idris presents this exercise:
same_cons : {xs : List a} -> {ys : List a} -> xs = ys -> x :: xs = x :: ys
However, I attempted to implement it via:
data EqList : (xs : List a) -> (ys : List a) -> Type where
Same : (xs: List a) -> EqList xs xs
sameS : (xs : List a) -> (ys : List a) -> (x: a) -> (eq : EqList xs ys) -> EqList (x :: xs) (x :: ys)
sameS xs xs x (Same xs) = Same (x :: xs)
same_cons : {xs : List a} -> {ys : List a} -> (eq : EqList xs ys) -> EqList (x :: xs) (x :: ys)
same_cons {xs} {ys} eq = sameS xs ys _ eq
I inferred the x
in EqList (x :: xs) (x :: ys)
because I'm confused how to get an x
if xs
and ys
are empty.
Also, the above compiles, but it failed when I tried to call it:
*Exercises> same_cons (Same [1,2,3])
(input):Can't infer argument x to same_cons
回答1:
The implicit argument x
cannot be inferred in your use case because there is no information in the call same_cons (Same [1,2,3])
to constrain it to anything. If you fix the type of the result, that will give you the choice of x
, e.g.
λΠ> the (EqList [0,1,2,3] [0,1,2,3]) (same_cons (Same [1,2,3]))
Same [0, 1, 2, 3] : EqList [0, 1, 2, 3] [0, 1, 2, 3]
since the choice of [0,1,2,3]
for x:xs
unifies x
with 0
.
BTW you can simplify the definition of same_cons
since the eq
argument's type determines xs
and ys
so you can let Idris infer it:
same_cons : (eq : EqList xs ys) -> EqList (x :: xs) (x :: ys)
same_cons eq = sameS _ _ _ eq
回答2:
To clarify on how to get the x
:
Everything in lowercase in the type decleration will become an implicit argument, if it isn't already explicit. So
same_cons : {xs : List a} -> {ys : List a} ->
(eq : EqList xs ys) -> EqList (x :: xs) (x :: ys)
is the same as
same_cons : {a : Type} -> {x : a} -> {xs : List a} -> {ys : List a} ->
(eq : EqList xs ys) -> EqList (x :: xs) (x :: ys)
That's where the x
is hiding. So you could use {x}
on the left hand side of the definition to get it. Or just let Idris handle all the stuff and use Cactus' definition. For future problems with arguments, you can use :set showimplicits
in the REPL to show you all the implicit arguments when asking for types, e.g. :t same_cons
.
And when Idris cannot infer the value for an implicit argument, you can help it by giving the resulting type like Cactus did or set the implicit argument to a value:
*> same_cons {x=0} (Same [3,2,5])
Same [0, 3, 2, 5] : EqList [0, 3, 2, 5] [0, 3, 2, 5]
来源:https://stackoverflow.com/questions/37063005/define-equality-of-lists-function