How to build a list of heterogeneous dependant pairs in Coq - list

I'd like to be able to have an heterogeneous sequence of dependent pairs (T, f) where T is in Set and f if a function T -> bool such as
Definition classif :
seq (forall T : Set, T -> bool) :=
[:: (fun b : bool => b); (fun n : nat => false)].
Note: I'm using SSReflect syntax for lists.
Clearly the type written above is not the right one.
Is it possible ?

#ThéoWinterhalter's answer is the way to go here. Just add a precision w.r.t. his answer [I initially posted it as a comment but that hindered the readability of the code…]:
the type you are looking for here is {T : Set & T -> bool}, it is a Σ-type and relies on the following inductive:
Print sigT.
Inductive sigT (A : Type) (P : A -> Type) : Type :=
existT : forall x : A, P x -> {x : A & P x}
And to ease your definition of classif, you could also define a shortcut:
From mathcomp Require Import all_ssreflect.
Set Implicit Arguments.
Definition sigma (T' : Set) f := (existT (fun A : Set => A -> bool) T' f).
Definition classif :
seq {T : Set & T -> bool} :=
[:: sigma (fun b : bool => b); sigma (fun n : nat => false)].

You're looking for dependent pairs and are writing dependent functions instead.
The type of pointed types is
{ A : Set & A }
Then you can build for instance the pair of nat and 1:
Check (existT (fun A : Set => A) nat 1) : { A : Set & A }.
It is nicer with some notations but there you have it.

Related

Single colon in OCaml

I'm confused with the syntax "single colon" in OCaml.
Snippet:
let update_variable (old_state : state) (var_name : var) (new_value : value) : var -> value option =
fun x -> if x = var_name then Some new_value else old_state x
The type inference of this function is state->var->value->value option. I'm confused with the colon before the var->value option. What does it mean? Is an additional parameter omitted?
A colon in OCaml is used to indicate typing. Usually, when you see something like ident : type, it means you're indicating ident has type type. For instance, you could do something
let a : int = 3
This also extends to function definition; however, in this case, since there are many identifiers before the =, it may confuse you about which identifier is being typed. Well, it's actually the whole thing before that is typed, the idea being that it will match what you have in your code. For instance, if you have something like
let f (x : 'a) : 'b =
...
it means f : 'a -> 'b. You could understand it as
let (f (x : 'a)) : 'b =
...
even though this is not valid syntax. This is because when, in your code, you will see something like f x, you'll know it will have type 'b.
Please note that explicit typing is rarely used in OCaml. In this case it is being used to give update_variable a more specific type than would otherwise be inferred.
Consider a simple, contrived example:
utop #
type foo = Foo
let f a b = a = b
let g (a : foo) (b : foo) = a = b;;
type foo = Foo
val f : 'a -> 'a -> bool = <fun>
val g : foo -> foo -> bool = <fun>
Without explicit type hints, in function f there is nothing know about parameters a and b except that they must be the same type.
We'd get the same behavior in g except that we've explicitly told it a and b must be of type foo. We can achieve the same by only specifying the type of one of the two parameters.
utop #
let h (a : foo) b = a = b;;
val h : foo -> foo -> bool = <fun>

inline locally abstract types in OCaml

Do I have to write a function to locally bind a type ?
Using an auxiliary function works, but trying to do so as part of a type decoration of a term during destructuring does not seem to work.
type ('a, 'b) eq
type 'a repr = TpFun : ('a, 'x -> 'y) eq -> 'a repr
let rewrite1 (type x y b f) (fxy : (f, x -> y) eq) : (f, x -> b) eq =
failwith ""
let eqp : type a b. a repr -> (a, b) eq = function
| TpFun (fxy) ->
let x = rewrite1 fxy in
_
let eqpFAIL : type a b. a repr -> (a, b) eq = function
| TpFun ((fxy : type x y. (a, x -> y) eq) ) ->
let x = failwith "" in
_
As described in https://ocaml.org/manual/gadts-tutorial.html#s%3Aexplicit-existential-name, the correct syntax for binding existential type in pattern is
let eqp : type a b. a repr -> (a, b) eq = function
| TpFun (type x y) (fxy :(a, x -> y) eq) ->
assert false
Beware also that you probably don't want to use an abstract type for eq since the type checker cannot infer any property on an abstract types that might have been defined as an abbreviation!
type ('a, 'b) eq = int
I am generally advising to use a type definition with an existing name:
type ('a,'b) eq = Eq
because that construction guarantees injectivity with respect to the type constructor parameters and allow the type checker to infer some type inequalities.

Monads and SML modules

signature MAPPABLE = sig
type 'a mappable
val fmap : ('a -> 'b) -> 'a mappable -> 'b mappable
end
structure Option : MAPPABLE = struct
type 'a mappable = 'a option
fun fmap f v =
case v of
(SOME x) => SOME (f x)
| NONE => NONE;
end
structure List : MAPPABLE = struct
type 'a mappable = 'a list
fun fmap f v = map f v
end
fun incByFive x = x + 5
Really just to have a function that does stuff with fmap
fun mapToPair f x =
let val b = List.fmap f x
in (b,b)
end
val lst = mapToPair incByFive [1,2,3];
Suppose you want to make a generic implementation, that works for
all instances of MAPPABLE. The following does not work
fun mapToPair f x =
let val b = MAPPABLE.fmap f x
in (b,b)
end
It seems, that SML people point to Functors, if that needs to be done.
I tried implementing one, for a generic implementation of mapToPair
functor FMAPFUNCTOR (structure Q : MAPPABLE)
= struct
fun mapToPair f x =
let val b = Q.fmap f x
in (b,b)
end
end;
However, to use it with what in Haskell I'd call a functor
instance, I need to instantiate the functor (this reminds me of C++
templates for some reason)
structure MAPPABLE_TO_PAIR = FMAPFUNCTOR (structure Q = List);
val lstByPoly = MAPPABLE_TO_PAIR.mapToPair incByFive [1,2,3]
I would have to repeat that instantiation for every MAPPABLE
instance I want to use. I guess Haskell performs something like this,
too. Just implicitly.
Now I wonder if there is any shortcut / sugar for a better "user
experience" in SML that I have missed. Because really, it seems kind
of a lot of boilerplate in the way in order to use this in a code
base.
I guess Haskell performs something like this, too. Just implicitly.
The Haskell standard library defines and imports a ton of type class instances. Given a sufficient set of ML functors, their applications and their implicit compile-time imports, you could achieve something quite convenient.
But Haskell does let you automate type class instance declarations in ways that SML doesn't.
For example, instance Foo t => Bar t where ... is comparable to SML's higher-order functors, but in SML you explicitly have to generate a module that corresponds to Bar t for each concrete Foo t. Haskell also lets you derive instances syntactically.
OCaml had modular implicits from 2014 (example), but they mainly give you syntax sugar to refer to defined functor instances, rather than generate them.
I suspect that the reason ML module systems are still more explicit than Haskell's is because of things like overlapping instances.
Andreas Rossberg contributed 1ML in 2014 in which modules are first-class citizens. That means a function could take a module as an argument, e.g. like this:
;; Higher-kinded polymorphism
type MONAD (m : type => type) =
{
return 'a : a -> m a;
bind 'a 'b : m a -> (a -> m b) -> m b;
};
map 'a 'b (m : type => type) (M : MONAD m) (f : a -> b) mx =
M.bind mx (fun x => M.return (f x));
do map :
'a => 'b => (m : type => type) => (M : MONAD m) => (a -> b) -> m a -> m b;
This is still research-y in the sense that the compiler has "TOY" in its name, but it'd be an example of an ML (although not Standard ML) that does something comparably generic with modules.

Parametrising over "higher-kinded" types in Idris

I just started playing around with Idris, and tried shoe-horning some Haskell machines into it:
namespace works
data Auto a b = AutoC (a -> (b, Auto a b))
const_auto : b -> Auto a b
const_auto b = AutoC (\_ => (b, const_auto b))
However, I'd like now to generalize Auto a b to AutoM m a b to take an extra parameter so it can generate its output monadically, with m being the monad. My intuition would have been that m would have type Type -> Type, but then the type-checker complains that that doesn't match (Type, Type) -> Type. So I tried leaving it a little more polymorphic:
namespace doesntwork
data AutoM : {x : Type } -> (m : x -> Type) -> (a : Type) -> (b : Type) -> Type where
AutoMC : (a -> m (b, AutoM m a b)) -> AutoM m a b
data Identity a = IdentityC a
Auto : Type -> Type -> Type
Auto = AutoM Identity
This at least type-checks. But when I try:
const_auto : Monad m => {m : x -> Type } -> {a : Type} -> b -> AutoM m a b
const_auto b = AutoMC (\_ => return (b, const_auto b))
That, however, is no good:
When elaborating right hand side of Stream.doesntwork.const_auto:
When elaborating an application of function Prelude.Monad.return:
Can't unify
(A, B) (Type of (a, b))
with
(b, AutoM m4 a b) (Expected type)
And I can't make much sense of the type error. Why in the world would the type of (a, b) be mentioned, when a isn't used anywhere in the definition of const_auto? I have the feeling the definition of AutoM itself is already at fault, but I don't really know why or how.
You were right when your intuition told you that m being a monad, it should have type Type -> Type. The problem here is that (,) is overloaded to mean both the Pair type constructor and the mkPair data constructor and Idris' elaborator makes the wrong choice.
By picking explicitly Pair, you fix the definition:
data AutoM : (m : Type -> Type) -> (a : Type) -> (b : Type) -> Type where
AutoMC : (a -> m (Pair b (AutoM m a b))) -> AutoM m a b
Now, if you just do that you'll get another cryptic message:
Auto.idr:18:14:
When elaborating right hand side of Main.doesntwork.const_auto:
Can't resolve type class Monad m3
Metavariables: Main.doesntwork.const_auto
The problem here is the fact that you introduce an implicit m in the type annotation of const_auto which is different from the one already introduced by the constraint Monad m => and so Idris cannot find a Monad instance for this new m. The solution is to not introduce it at all (the constraint mentioning an m being enough for it to be in scope) like so:
const_auto : Monad m => {a : Type} -> b -> AutoM m a b

OCaml: higher kinded polymorphism (abstracting over modules?)

Let's say I have a list of options:
let opts = [Some 1; None; Some 4]
I'd like to convert these into an option of list, such that:
If the list contains None, the result is None
Otherwise, the various ints are collected.
It's relatively straightforward to write this for this specific case (using Core and the Monad module):
let sequence foo =
let open Option in
let open Monad_infix in
List.fold ~init:(return []) ~f:(fun acc x ->
acc >>= fun acc' ->
x >>= fun x' ->
return (x' :: acc')
) foo;;
However, as the question title suggests, I'd really like to abstract over the type constructor rather than specialising to Option. Core seems to use a functor to give the effect of a higher kinded type, but I'm not clear how I can write the function to be abstracted over the module. In Scala, I'd use an implicit context bound to require the availability of some Monad[M[_]]. I'm expecting that there's no way of implicitly passing in the module, but how would I do it explicitly? In other words, can I write something approximating this:
let sequence (module M : Monad.S) foo =
let open M in
let open M.Monad_infix in
List.fold ~init:(return []) ~f:(fun acc x ->
acc >>= fun acc' ->
x >>= fun x' ->
return (x' :: acc')
) foo;;
Is this something that can be done with first class modules?
Edit: Okay, so it didn't actually occur to me to try using that specific code, and it appears it's closer to working than I'd anticipated! Seems the syntax is in fact valid, but I get this result:
Error: This expression has type 'a M.t but an expression was expected of type 'a M.t
The type constructor M.t would escape its scope
The first part of the error seems confusing, since they match, so I'm guessing the problem is with the second - Is the problem here that the return type doesn't seem to be determined? I suppose it's dependent on the module which is passed in - is this a problem? Is there a way to fix this implementation?
First, here is a self-contained version of your code (using the legacy
List.fold_left of the standard library) for people that don't have
Core under hand and still want to try to compile your example.
module type MonadSig = sig
type 'a t
val bind : 'a t -> ('a -> 'b t) -> 'b t
val return : 'a -> 'a t
end
let sequence (module M : MonadSig) foo =
let open M in
let (>>=) = bind in
List.fold_left (fun acc x ->
acc >>= fun acc' ->
x >>= fun x' ->
return (x' :: acc')
) (return []) foo;;
The error message that you get means (the confusing first line can
be ignored) that the M.t definition is local to the M module, and
must not escape its scope, which it would do with what you're trying
to write.
This is because you are using first-class modules, that allow to
abstract on modules, but not to have dependent-looking types such as
the return type depends on the argument's module value, or at least
path (here M).
Consider this example:
module type Type = sig
type t
end
let identity (module T : Type) (x : T.t) = x
This is wrong. The error messages points on (x : T.t) and says:
Error: This pattern matches values of type T.t
but a pattern was expected which matches values of type T.t
The type constructor T.t would escape its scope
What you can do is abstract on the desired type before you abstract on the first-class module T, so that there is no escape anymore.
let identity (type a) (module T : Type with type t = a) (x : a) = x
This relies on the ability to explicitly abstract over the type variable a. Unfortunately, this feature has not been extended to abstraction over higher-kinded variables. You currently cannot write:
let sequence (type 'a m) (module M : MonadSig with 'a t = 'a m) (foo : 'a m list) =
...
The solution is to use a functor: instead of working at value level, you work at the module level, which has a richer kind language.
module MonadOps (M : MonadSig) = struct
open M
let (>>=) = bind
let sequence foo =
List.fold_left (fun acc x ->
acc >>= fun acc' ->
x >>= fun x' ->
return (x' :: acc')
) (return []) foo;;
end
Instead of having each monadic operation (sequence, map, etc.) abstract over the monad, you do a module-wide abstraction.