Naming return value in Idris? - idris

In Idris, one can explicitly name arguments in function type declarations, like
length : (str : String) -> Nat
But when I try to name the return value, like in
length : (str : String) -> (lengthOfStr : Nat)
the idris compiler throws an error
unexpected end of input
expecting "->"
Why doesn't the same syntax for naming arguments work for return values? Is there a way to name return values in Idris (so they can be referenced in the doc-string)?

No, that's not possible, see this issue. Your question about doc-string might change some opinions, why not ask there? But there might be a problem: someone might think that e.g. f: (n : Nat) -> (n : Nat) is valid and would only allow f n = n as an implementation. But you can't specify the return value, only the return type.

Related

Partial application of Printf.ksprintf

I'm trying to write a version of Printf.printf that always appends a newline character after writing its formatted output. My first attempt was
# let say fmt = Printf.ksprintf print_endline fmt;;
val say : ('a, unit, string, unit) format4 -> 'a = <fun>
The type signature looks right and say works as expected. I noticed that fmt is listed twice, and thought that partial application could eliminate it. So I tried this instead:
# let say = Printf.ksprintf print_endline;;
val say : ('_weak1, unit, string, unit) format4 -> '_weak1 = <fun>
The function definition looks cleaner, but the type signature looks wrong and say no longer works as expected. For example, say doesn't type check if the format string needs a variable number of arguments: I get an error that say "is applied to too many arguments".
I can use the let say fmt = … implementation, but why doesn't partial application work?
OCaml's type-checker loses polymorphism during partial application. That is, when you partially apply a function, the resulting function is no longer polymorphic. That's why you see '_weak1 in the second type signature.
When you include the fmt argument, you help the type-checker recognize that polymorphism is still present.
This process is called "eta conversion." Removing your fmt argument is "eta reduction" and adding it back in is called "eta expansion." You may encounter that terminology when working with other functional programming languages.
This is the value restriction at work: https://ocaml.org/manual/polymorphism.html#s:weak-polymorphism . In brief, only syntactic values can be safely generalized in let-binding in presence of mutable variables in the language.
In particular,
let f = fun x -> g y x
is a syntactic value that can be generalized, whereas
let f = g y
is a computation that cannot (always) be generalized.
A example works quite well to illustrate the issue, consider:
let fake_pair x =
let store = ref None in
fun y ->
match !store with
| None ->
store := Some y;
x, y
| Some s ->
x, s
then the type of fake_pair is 'a -> 'b -> 'a * 'b.
However, once partially applied
let p = fake_pair 0
we have initialized the store mutable value, and it is important that all subsequent call to p share the same type (because they must match the stored value). Thus the type of p is '_weak1 -> int * '_weak1 where '_weak1 is a weak type variable, aka a temporary placeholder for a concrete type.

Defining a type using a recursive Type -> Type function

In Idris, normally List is defined like so:
data List a = Nil | (::) a (List a)
But I wanted to try defining List without data, using a recursive Type -> Type function:
List' : Type -> Type
List' a = Either () (a, List' a)
This compiles, but I cannot match on the Either cases. For example, if I define
isEmpty : List' a -> Bool
isEmpty (Left _) = True
isEmpty (Right _) = False
the compiler says:
When checking left hand side of isEmpty:
When checking an application of Main.isEmpty:
Type mismatch between
Either a1 b (Type of Left l)
and
List' a (Expected type)
So the typechecker doesn't seem to expand List' a into its Either _ _ definition. It seems that the recursive call in the type definition trips up the typechecker -- if I instead define List' like so:
List' a = Either () (a, ())
then the isEmpty definition compiles fine. (But of course it's not actually a list anymore.)
What I'd like to know is:
Why exactly does this not work? Is there a way to inspect what is going on inside the typechecker?
Is there a way to make this kind of type definition work? Or do we have to use data?

List of types from a function type

I would like to make a function that given a function type (e.g. String -> Nat -> Bool), would return a list of types corresponding to that function type (e.g. [String, Nat, Bool]). Presumably the signature of such a function would be Type -> List Type, but I am struggling to determine how it would be implemented.
I don't believe it could be done in general, because you cannot patter-match on functions. Neither can you check for the type of a function. That is not what dependent types are about. Just like in Haskell or OCaml the only thing you can actually do with a function is apply it to some argument. However, I devised some trick which might do:
myFun : {a, b : Type} -> (a -> b) -> List Type
myFun {a} {b} _ = [a, b]
Now the problem is that a -> b is the only signature that would match any arbitrary function. But, of course it does not behave the way you'd like for functions with arity higher than one:
> myFun (+)
[Integer, Integer -> Integer] : List Type
So some sort of recursive call to itself would be necessary to extract more argument types:
myFun : {a, b : Type} -> (a -> b) -> List Type
myFun {a} {b} _ = a :: myFun b
The problem here is that b is an arbitrary type, not necessarily a function type and there is no way I can figure out to dynamically check whether it is a function or not, so I suppose this is as much as you can do with Idris.
However, dynamic checking for types (at least in my opinion) is not a feature to be desired in a statically typed language. After all the whole point of static typing is to specify in advance what kind of arguments a function can handle and prevent calling functions with invalid arguments at compile time. So basically you probably don't really need it at all. If you specified what you grander goal was, someone would likely have shown you the right way of doing it.

Choosing a typeclass on construction of a data type

I have a a data type in idris:
data L3 = Rejected | Unproven | Proven
which I verified to be a ring with unity, a lattice, a group and some other properties too.
Now I want to create an object, which preserves the expressions of the statements I inject in it. I started out with four categories to represent all the operations, so I get a nice syntax tree out of it. Eg:
Om [Proven, Unproven, Op [Proven, Oj [Unproven, Proven]]
This is not the real representation, I stripped some of the needed ugly parts, but it gives an idea of what I try to achieve, the above is equivalent to:
meet Proven (meet Unproven (Proven <+> (join Unproven Proven)))
I recognized I could join the data types together into one. To get there I created a function, which will pick the correct class instance:
%case data Operator = Join | Meet | Plus | Mult
classChoice : (x: Operator) -> (Type -> Type)
classChoice Join = VerifiedJoinSemilattice
classChoice Meet = VerifiedMeetSemilattice
classChoice Plus = VerifiedGroup
classChoice Mult = VerifiedRing
So I could assure that anything in the type represents one of those four operations:
%elim data LogicSyntacticalCategory : classChoice op a => (op : Operator) -> (a : Type) -> Type where
LSCEmpty : LogicSyntacticalCategory op a
It will complain with:
When elaborating type of logicCategory.LSCEmpty:
Can't resolve type class classChoice op ty
Now my question: How can I assure that the objects in my data type are verified and join the four separate data types into one. I really would like to ensure this is true during construction. I can understand it has difficulties resolving the type class now, but I want Idris to ensure it can do it later during construction. How can I do this?
Code isn't really needed, I am quite happy with a direction of thought.
Two minor problems first: ... -> a -> ... should be ... -> (a : Type) -> ..., and syntactical is how it's written.
Warning: I'm working with Idris 0.9.18 and don't know how to write Elab proofs yet.
Repository: https://github.com/runKleisli/idris-classdata
In normal functions with these same type signatures, you have the opportunity to assist the type class resolution with tactics while defining the functions. But with the data type and its constructors, you only have the opportunity to declare them, so you have no such opportunity to assist in resolution. It would appear such guided resolution was needed here.
It appears that classChoice op a needs an instance proved before the LogicSyntacticleCategory op a in the definition of LSCEmpty makes sense, and that it did not get this instance. Class constraints in the data type's type like this are usually automatically introduced into the context of the constructor, like an implicit argument, but this seems to have failed here, and an instance is assumed for a different type than the one required. That instance assumed for the constructor not satisfying the goal introduced by declaring a LogicSyntacticleCategory op a seems to be the error. In one of the examples in the repository, these unexpectedly mismatched goal and assumption seem able to automatically pair, but not under the circumstances of the data type & constructor declarations. I can't figure out the exact problem, but it seems not to apply to plain function declarations with the same conditions on the type signature.
A couple solutions are given in the repository, but the easiest one is to replace the constraint argument, saying an instance of classChoice op a is required, with an implicit argument of type classChoice op a, and to evaluate LogicSyntacticleCategory like
feat : Type
feat = ?feat'
feat' = proof
exact (LogicSyntacticleCategory Mult ZZ {P=%instance})
If you are set on having a constraint argument in your main interface to the data type, you can wrap the definition of LogicSyntacticleCategory : (op : Operator) -> (a : Type) -> {p : classChoice op a} -> Type with the function
logicSyntacticleCategory : classChoice op a => (op : Operator) -> (a : Type) -> Type
logicSyntacticleCategory = ?mkLogical
mkLogical = proof
intros
exact (LogicSyntacticleCategory op a {P=constrarg})
and when you want to make a type of the form LogicSyntacticleCategory op a, evaluate like before, but with
feat' = proof
exact (logicSyntacticleCategory Mult ZZ)
exact Mult
exact ZZ
compute
exact inst -- for the named instance (inst) of (classChoice Mult ZZ)
where the last line is dropped for anonymous instances.

Is there a nice way to use `->` directly as a function in Idris?

One can return a type in a function in Idris, for example
t : Type -> Type -> Type
t a b = a -> b
But the situation came up (when experimenting with writing some parsers) that I wanted to use -> to fold a list of types, ie
typeFold : List Type -> Type
typeFold = foldr1 (->)
So that typeFold [String, Int] would give String -> Int : Type. This doesn't compile though:
error: no implicit arguments allowed
here, expected: ")",
dependent type signature,
expression, name
typeFold = foldr1 (->)
^
But this works fine:
t : Type -> Type -> Type
t a b = a -> b
typeFold : List Type -> Type
typeFold = foldr1 t
Is there a better way to work with ->, and if not is it worth raising as a feature request?
The problem with using -> in this way is that it's not a type constructor but a binder, where the name bound for the domain is in scope in the range, so -> itself doesn't have a type directly. Your definition of t for example wouldn't capture a dependent type like (x : Nat) -> P x.
While it is a bit fiddly, what you're doing is the right way to do this. I'm not convinced we should make special syntax for (->) as a type constructor - partly because it really isn't one, and partly because it feels like it would lead to more confusion when it doesn't work with dependent types.
The Data.Morphisms module provides something like this, except you have to do all the wrapping/unwrapping around the Morphism "newtype".