Trying to bring implicit argument into scope on the left side of a definition in Idris results in "is f applied to too many arguments" error - idris

The function applyRule is supposed to extract the implicit argument n that is used in another arguments it gets, of type VVect.
data IVect : Vect n ix -> (ix -> Type) -> Type where -- n is here
Nil : IVect Nil b
(::) : b i -> IVect is b -> IVect (i :: is) b
VVect : Vect n Nat -> Type -> Type -- also here
VVect is a = IVect is (flip Vect a)
-- just for completeness
data Expression = Sigma Nat Expression
applyRule : (signals : VVect is Double) ->
(params : List Double) ->
(sigmas : List Double) ->
(rule : Expression) ->
Double
applyRule {n} signals params sigmas (Sigma k expr1) = cast n
Without referring to {n}, the code type-checks (if cast n is changed to some valid double). Adding it in, however, results in the following error:
When checking left hand side of applyRule:
Type mismatch between
Double (Type of applyRule signals params sigmas rule)
and
_ -> _ (Is applyRule signals
params
sigmas
rule applied to too many arguments?)
This doesn't seem to make sense to me, because I'm not pattern-matching on any parameter that could have a dependency on n, so I thought that simply putting it in curly braces would bring it into scope.

You can only bring n into scope if it is defined somewhere (e.g. as a variable in the arguments). Otherwise it would be hard to figure out where the n comes from – at least for a human.
applyRule : {is : Vect n Nat} ->
(signals : VVect is Double) ->
(params : List Double) ->
(sigmas : List Double) ->
(rule : Expression) ->
Double
applyRule {n} signals params sigmas (Sigma k expr1) = cast n

Related

Is there a notion of "heterogenous collection of a given shape"?

A common pattern in functional programming languages with a sufficiently advanced type system to to have a type of "heterogeneous lists". For instance, given a list defined as:
data List a = Nil | Cons a (List a)
(Note: For concreteness, I will use Idris in this question, but this could also be answered in Haskell (with the right extensions), Agda, etc...)
We can define HList:
data HList : List a -> Type where
Nil : HList []
(::) : a -> HList as -> HList (a :: as)
This is a list which holds a different type (specified by the type-level List a) at each "position" of the List data type. This made me wonder: Can we generalize this construction? For instance, given a simple tree-like structure:
data Tree a = Branch a [Tree a]
Does it make sense to define a heterogenous tree?
where HTree : Tree a -> Type where
...
More generally in a dependently-typed language, is it possible to define a general construction:
data Hetero : (f : Type -> Type) -> f a -> Type where
....
that takes a data type of kind Type -> Type and returns the "heterogeneous container" of shape f? Has anyone made use of this construction before if possible?
We can talk about the shape of any functor using map and propositional equality. In Idris 2:
Hetero : (f : Type -> Type) -> Functor f => f Type -> Type
Hetero f tys = (x : f (A : Type ** A) ** map fst x = tys)
The type (A : Type ** A) is the type of non-empty types, in other words, values of arbitrary type. We get heterogeneous collections by putting arbitrarily typed values into functors, then constraining the types elementwise to particular types.
Some examples:
ex1 : Hetero List [Bool, Nat, Bool]
ex1 = ([(_ ** True), (_ ** 10), (_ ** False)] ** Refl)
data Tree : Type -> Type where
Leaf : a -> Tree a
Node : Tree a -> Tree a -> Tree a
Functor Tree where
map f (Leaf a) = Leaf (f a)
map f (Node l r) = Node (map f l) (map f r)
ex2 : Hetero Tree (Node (Leaf Bool) (Leaf Nat))
ex2 = (Node (Leaf (_ ** False)) (Leaf (_ ** 10)) ** Refl)

How to use data from Maybe as Vect size variable

I'm trying to write a simple program that asks the user about the list size and shows content from that list by index also by the user's input. But I've stuck. I have a function that builds a list by a number. Now I want to create another function that uses Maybe Nat as input and returns Maybe (Vect n Nat). But I have no idea how to accomplish this. Here is the code:
module Main
import Data.Fin
import Data.Vect
import Data.String
getList: (n: Nat) -> Vect n Nat
getList Z = []
getList (S k) = (S k) :: getList k
mbGetList : (Maybe Nat) -> Maybe (Vect n Nat)
mbGetList mbLen = case mbLen of
Just len => Just (getList len)
Nothing => Nothing
main : IO ()
main = do
len <- readNum
-- list <- mbGetList len
putStrLn (show len)
And here is the error:
|
55 | Just len => Just (getList len)
| ~~~~~~~~~~~
When checking right hand side of Main.case block in mbGetList at main.idr:54:24-28 with expected type
Maybe (Vect n Nat)
When checking argument n to function Main.getList:
Type mismatch between
n (Inferred value)
and
len (Given value)
I've tried to declare an implicit variable. The code compiles, but I can't use it (at least throw repl). Also, I've tried to use dependant pair and also failed. Maybe I should use Dec instead of Maybe? But how??? Another attempt was a try to use map function. But in that case, I have an error like that: Can't infer argument n to Functor.
So, what I've missed?
This answer doesn't feel optimal, but here goes
mbGetList : (mbLen: Maybe Nat) -> case mbLen of
(Just len) => Maybe (Vect len Nat)
Nothing => Maybe (Vect Z Nat)
mbGetList (Just len) = Just (getList len)
mbGetList Nothing = Nothing
I think the difficulty comes from the fact that there's no well-defined length for the Vect if you don't have a valid input

Defining groups in Idris

I defined monoid in Idris as
interface Is_monoid (ty : Type) (op : ty -> ty -> ty) where
id_elem : () -> ty
proof_of_left_id : (a : ty) -> ((op a (id_elem ())) = a)
proof_of_right_id : (a : ty) -> ((op (id_elem ())a) = a)
proof_of_associativity : (a, b, c : ty) -> ((op a (op b c)) = (op (op a b) c))
then tried to define groups as
interface (Is_monoid ty op) => Is_group (ty : Type) (op : ty -> ty -> ty) where
inverse : ty -> ty
proof_of_left_inverse : (a : ty) -> (a = (id_elem ()))
but during compilation it showed
When checking type of Group.proof_of_left_inverse:
Can't find implementation for Is_monoid ty op
Is there a way around it.
The error message is a bit misleading, but indeed, the compiler does not know which implementation of Is_monoid to use for your call to id_elem in your definition of proof_of_left_inverse. You can make it work by making it making the call more explicit:
proof_of_left_inverse : (a : ty) -> (a = (id_elem {ty = ty} {op = op} ()))
Now, why is this necessary? If we have a simple interface like
interface Pointed a where
x : a
we can just write a function like
origin : (Pointed b) => b
origin = x
without specifying any type parameters explicitly.
One way to understand this is to look at interfaces and implementations through the lens of other, in a way more basic Idris features. x can be thought of as a function
x : {a : Type} -> {auto p : PointedImpl a} -> a
where PointedImpl is some pseudo type that represents the implementations of Pointed. (Think a record of functions.)
Similarly, origin looks something like
origin : {b : Type} -> {auto j : PointedImpl b} -> b
x notably has two implicit arguments, which the compiler tries to infer during type checking and unification. In the above example, we know that origin has to return a b, so we can unify a with b.
Now i is also auto, so it is not only subject to unification (which does not help here), but in addition, the compiler looks for "surrounding values" that can fill that hole if no explicit one was specified. The first place to look after local variables which we don't have is the parameter list, where we indeed find j.
Thus, our call to origin resolves without us having to explicitly specify any additional arguments.
Your case is more akin to this:
interface Test a b where
x : a
y : b
test : (Test c d) => c
test = x
This will error in the same manner your example did. Going through the same steps as above, we can write
x : {a : Type} -> {b -> Type} -> {auto i : TestImpl a b} -> a
test : {c : Type} -> {d -> Type} -> {auto j : TestImpl c d} -> c
As above, we can unify a and c, but there is nothing that tells us what d is supposed to be. Specifically, we can't unify it with b, and consequently we can't unify TestImpl a b with TestImpl c d and thus we can't use j as value for the auto-parameter i.
Note that I don't claim that this is how things are implemented under the covers. This is just an analogy in a sense, but one that holds up to at least some scrutiny.

Create a zero length vector

Given this type for vectors, what's the way to create a zero length vector of a particular type of items?
data Vect : Nat -> Type -> Type where
VectNil : Vect 0 ty
(::) : ty -> Vect size ty -> Vect (S size) ty
VectNil String and all the variations I've tried in the REPL failed.
Is it not correct to expect VectNil to work like the default constructor of the generic List in C# does?
new List<string> (); // creates a zero length List of string
VecNil is value constructor and it accepts implicit type parameter. Here you can see it in REPL:
*x> :set showimplicits
*x> :t VectNil
Main.VectNil : {ty : Type} -> Main.Vect 0 ty
Idris infers values of those implicit parameters from the context. But sometimes context does not have enough information:
*x> VectNil
(input):Can't infer argument ty to Main.VectNil
You can explicitly provide value for implicit parameter using braces:
*x> VectNil {ty=String}
Main.VectNil {ty = String} : Main.Vect 0 String
Or use the the operator to add a type annotation:
*x> the (Vect 0 String) VectNil
Main.VectNil : Main.Vect 0 String
In larger programs, Idris is able to infer the type based on its use site.

Strange error message with Idris interfaces

I'm trying to implement a simple algebraic structures hierarchy using Idris interfaces. The code is as follows:
module AlgebraicStructures
-- definition of some algebraic structures in terms of type classes
%access public export
Associative : {a : Type} -> (a -> a -> a) -> Type
Associative {a} op = (x : a) ->
(y : a) ->
(z : a) ->
(op x (op y z)) = (op (op x y) z)
Identity : {a : Type} -> (a -> a -> a) -> a -> Type
Identity op v = ((x : a) -> (op x v) = x,
(x : a) -> (op v x) = x)
Commutative : {a : Type} -> (a -> a -> a) -> Type
Commutative {a} op = (x : a) ->
(y : a) ->
(op x y) = (op y x)
infixl 4 <**>
interface IsMonoid a where
empty : a
(<**>) : a -> a -> a
assoc : Associative (<**>)
ident : Identity (<**>) empty
interface IsMonoid a => IsCommutativeMonoid a where
comm : Commutative (<**>)
But, Idris is giving this strange error message:
When checking type of constructor of AlgebraicStructures.IsCommutativeMonoid:
Can't find implementation for IsMonoid a
I believe that Idris interfaces works like Haskell's type classes. In Haskell, it should work. Am I doing something silly?
I believe it may be complaining because I don't know that there's anything that constrains the a in the expression Commutative (<**>) - so it doesn't know that you can invoke <**> on that type.
Explicitly specifying the a seems to work for me - Commutative {a} (<**>) - I hope that that means that the a from the interface signature is in scope and available for explicitly passing to other types.