Can I write a generic function-wrapping function for a Wrapper interface representing a type that wraps some other type? - wrapper

The full code example below (which successfully compiles) is a simplified and slightly contrived example of my problem.
NatPair is a pair of Nats, and I want to "lift" the binaryNum operations to NatPair pointwise, using the function lift_binary_op_to_pair.
But I can't implement Num NatPair because NatPair is not a data constructor.
So, I wrap it in a type WrappedNatPair, and I can provide a Num implementation for that type, with corresponding 'lifted' versions of + and *.
Then I want to generalise the idea of a wrapper type, with my Wrapper interface.
The function lift_natpair_bin_op_to_wrapped can lift a binary operation from NatPair
to WrappedNatPair, and the implementation code is entirely in terms of the unwrap and
wrap Wrapper interface methods.
But, if I try to generalise to
lift_bin_op_to_wrapped : Wrapper t => BinaryOp WrappedType -> BinaryOp t
then the type signature won't even compile, with error:
`-- Wrapping.idr line 72 col 23:
When checking type of Main.lift_bin_op_to_wrapped:
Can't find implementation for Wrapper t
(where the error location is the location of ':' in the type signature).
I think the problem is that t doesn't appear anywhere in the
type signature for the Wrapper interface WrapperType method,
so WrapperType can't be invoked anywhere other than inside
the interface definition itself.
(The workaround is to write boilerplate lift_<wrapped>_bin_op_to_<wrapper> methods with the same implementation code op x y = wrap $ op (unwrap x) (unwrap y) each time, which is not intolerable. But I would like to have a clear understanding of why I can't write the generic lift_bin_op_to_wrapped method.)
The full code which successfully compiles:
%default total
PairedType : (t : Type) -> Type
PairedType t = (t, t)
NatPair : Type
NatPair = PairedType Nat
data WrappedNatPair : Type where
MkWrappedNatPair : NatPair -> WrappedNatPair
equal_pair : t -> PairedType t
equal_pair x = (x, x)
BinaryOp : Type -> Type
BinaryOp t = t -> t -> t
lift_binary_op_to_pair : BinaryOp t -> BinaryOp (PairedType t)
lift_binary_op_to_pair op (x1, x2) (y1, y2) = (op x1 y1, op x2 y2)
interface Wrapper t where
WrappedType : Type
wrap : WrappedType -> t
unwrap : t -> WrappedType
Wrapper WrappedNatPair where
WrappedType = NatPair
wrap x = MkWrappedNatPair x
unwrap (MkWrappedNatPair x) = x
lift_natpair_bin_op_to_wrapped : BinaryOp NatPair -> BinaryOp WrappedNatPair
lift_natpair_bin_op_to_wrapped op x y = wrap $ op (unwrap x) (unwrap y)
Num WrappedNatPair where
(+) = lift_natpair_bin_op_to_wrapped (lift_binary_op_to_pair (+))
(*) = lift_natpair_bin_op_to_wrapped (lift_binary_op_to_pair (*))
fromInteger x = wrap $ equal_pair (fromInteger x)
WrappedNatPair_example : the WrappedNatPair 8 = (the WrappedNatPair 2) + (the WrappedNatPair 6)
WrappedNatPair_example = Refl
(Platform: Ubuntu 16.04 running Idris 1.1.1-git:83b1bed.)

I think the problem is that t doesn't appear anywhere in the type signature for the Wrapper interface WrapperType method, so WrapperType can't be invoked anywhere other than inside the interface definition itself.
You're right here. This is why you receive this error. You can fix this compilation error by explicitly specifying which types is wrapper like this:
lift_bin_op_to_wrapped : Wrapper w => BinaryOp (WrappedType {t=w}) -> BinaryOp w
lift_bin_op_to_wrapped {w} op x y = ?hole
But this probably won't help you because Idris somehow cannot deduce correspondence between w and WrappedType. I would love to see explanation of this fact. Basically compiler (I'm using Idris 1.0) says me next things:
- + Wrap.hole [P]
`-- w : Type
x : w
y : w
constraint : Wrapper w
op : BinaryOp WrappedType
-----------------------------------
Wrap.hole : w
Your WrappedType dependently typed interface method implements pattern matching on types in some tricky way. I think this might be a reason why you have problems. If you're familiar with Haskell you might see some similarities between your WrappedType and -XTypeFamilies. See this question:
Pattern matching on Type in Idris
Though you still can implement general wrapper function. You only need to desing your interface differently. I'm using trick described in this question: Constraining a function argument in an interface
interface Wraps (from : Type) (to : Type) | to where
wrap : from -> to
unwrap : to -> from
Wraps NatPair WrappedNatPair where
wrap = MkWrappedNatPair
unwrap (MkWrappedNatPair x) = x
lift_bin_op_to_wrapped : Wraps from to => BinaryOp from -> BinaryOp to
lift_bin_op_to_wrapped op x y = wrap $ op (unwrap x) (unwrap y)
Num WrappedNatPair where
(+) = lift_bin_op_to_wrapped (lift_binary_op_to_pair {t=Nat} (+))
(*) = lift_bin_op_to_wrapped (lift_binary_op_to_pair {t=Nat}(*))
fromInteger = wrap . equal_pair {t=Nat} . fromInteger
This compiles and works perfectly.

Related

The signature for this packaged module couldn't be inferred in recursive function

I'm still trying to figure out how to split code when using mirage and it's myriad of first class modules.
I've put everything I need in a big ugly Context module, to avoid having to pass ten modules to all my functions, one is pain enough.
I have a function to receive commands over tcp :
let recvCmds (type a) (module Ctx : Context with type chan = a) nodeid chan = ...
After hours of trial and errors, I figured out that I needed to add (type a) and the "explicit" type chan = a to make it work. Looks ugly, but it compiles.
But if I want to make that function recursive :
let rec recvCmds (type a) (module Ctx : Context with type chan = a) nodeid chan =
Ctx.readMsg chan >>= fun res ->
... more stuff ...
|> OtherModule.getStorageForId (module Ctx)
... more stuff ...
recvCmds (module Ctx) nodeid chan
I pass the module twice, the first time no problem but
I get an error on the recursion line :
The signature for this packaged module couldn't be inferred.
and if I try to specify the signature I get
This expression has type a but an expression was expected of type 'a
The type constructor a would escape its scope
And it seems like I can't use the whole (type chan = a) thing.
If someone could explain what is going on, and ideally a way to work around it, it'd be great.
I could just use a while of course, but I'd rather finally understand these damn modules. Thanks !
The pratical answer is that recursive functions should universally quantify their locally abstract types with let rec f: type a. .... = fun ... .
More precisely, your example can be simplified to
module type T = sig type t end
let rec f (type a) (m: (module T with type t = a)) = f m
which yield the same error as yours:
Error: This expression has type (module T with type t = a)
but an expression was expected of type 'a
The type constructor a would escape its scope
This error can be fixed with an explicit forall quantification: this can be done with
the short-hand notation (for universally quantified locally abstract type):
let rec f: type a. (module T with type t = a) -> 'never = fun m -> f m
The reason behind this behavior is that locally abstract type should not escape
the scope of the function that introduced them. For instance, this code
let ext_store = ref None
let store x = ext_store := Some x
let f (type a) (x:a) = store x
should visibly fail because it tries to store a value of type a, which is a non-sensical type outside of the body of f.
By consequence, values with a locally abstract type can only be used by polymorphic function. For instance, this example
let id x = x
let f (x:a) : a = id x
is fine because id x works for any x.
The problem with a function like
let rec f (type a) (m: (module T with type t = a)) = f m
is then that the type of f is not yet generalized inside its body, because type generalization in ML happens at let definition. The fix is therefore to explicitly tell to the compiler that f is polymorphic in its argument:
let rec f: 'a. (module T with type t = 'a) -> 'never =
fun (type a) (m:(module T with type t = a)) -> f m
Here, 'a. ... is an universal quantification that should read forall 'a. ....
This first line tells to the compiler that the function f is polymorphic in its first argument, whereas the second line explicitly introduces the locally abstract type a to refine the packed module type. Splitting these two declarations is quite verbose, thus the shorthand notation combines both:
let rec f: type a. (module T with type t = a) -> 'never = fun m -> f m

Theorem Proving in Idris

I was reading Idris tutorial. And I can't understand the following code.
disjoint : (n : Nat) -> Z = S n -> Void
disjoint n p = replace {P = disjointTy} p ()
where
disjointTy : Nat -> Type
disjointTy Z = ()
disjointTy (S k) = Void
So far, what I figure out is ...
Void is the empty type which is used to prove something is impossible.
replace : (x = y) -> P x -> P y
replace uses an equality proof to transform a predicate.
My questions are:
which one is an equality proof? (Z = S n)?
which one is a predicate? the disjointTy function?
What's the purpose of disjointTy? Does disjointTy Z = () means Z is in one Type "land" () and (S k) is in another land Void?
In what way can an Void output represent contradiction?
Ps. What I know about proving is "all things are no matched then it is false." or "find one thing that is contradictory"...
which one is an equality proof? (Z = S n)?
The p parameter is the equality proof here. p has type Z = S n.
which one is a predicate? the disjointTy function?
Yes, you are right.
What's the purpose of disjointTy?
Let me repeat the definition of disjointTy here:
disjointTy : Nat -> Type
disjointTy Z = ()
disjointTy (S k) = Void
The purpose of disjointTy is to be that predicate replace function needs. This consideration determines the type of disjointTy, viz. [domain] -> Type. Since we have equality between naturals numbers, [domain] is Nat.
To understand how the body has been constructed we need to take a look at replace one more time:
replace : (x = y) -> P x -> P y
Recall that we have p of Z = S n, so x from the above type is Z and y is S n. To call replace we need to construct a term of type P x, i.e. P Z in our case. This means the type P Z returns must be easily constructible, e.g. the unit type is the ideal candidate for this. We have justified disjointTy Z = () clause of the definition of disjointTy. Of course it's not the only option, we could have used any other inhabited (non-empty) type, like Bool or Nat, etc.
The return value in the second clause of disjointTy is obvious now -- we want replace to return a value of Void type, so P (S n) has to be Void.
Next, we use disjointTy like so:
replace {P = disjointTy} p ()
^ ^ ^
| | |
| | the value of `()` type
| |
| proof term of Z = S n
|
we are saying "this is the predicate"
As a bonus, here is an alternative proof:
disjoint : (n : Nat) -> Z = S n -> Void
disjoint n p = replace {P = disjointTy} p False
where
disjointTy : Nat -> Type
disjointTy Z = Bool
disjointTy (S k) = Void
I have used False, but could have used True -- it doesn't matter. What matters is our ability to construct a term of type disjointTy Z.
In what way can an Void output represent contradiction?
Void is defined like so:
data Void : Type where
It has no constructors! There is no way to create a term of this type whatsoever (under some conditions: like Idris' implementation is correct and the underlying logic of Idris is sane, etc.). So if some function claims it can return a term of type Void there must be something fishy going on. Our function says: if you give me a proof of Z = S n, I will return a term of the empty type. This means Z = S n cannot be constructed in the first place because it leads to a contradiction.
Yes, p : x = y is an equality proof. So p is a equality proof and Z = S k is a equality type.
Also yes, usually any P : a -> Type is called predicate, like IsSucc : Nat -> Type. In boolean logic, a predicate would map Nat to true or false. Here, a predicate holds, if we can construct a proof for it. And it is true, if we can construct it (prf : ItIsSucc 4). And it is false, if we cannot construct it (there is no member of ItIsSucc Z).
At the end, we want Void. Read the replace call as Z = S k -> disjointTy Z -> disjointTy (S k), that is Z = S K -> () -> Void. So replace needs two arguments: the proof p : Z = S k and the unit () : (), and voilĂ , we have a void. By the way, instead of () you could use any type that you can construct, e.g. disjointTy Z = Nat and then use Z instead of ().
In dependent type theory we construct proofs like prf : IsSucc 4. We would say, we have a proof prf that IsSucc 4 is true. prf is also called a witness for IsSucc 4. But with this alone we could only proove things to be true. This is the definiton for Void:
data Void : Type where
There is no constructor. So we cannot construct a witness that Void holds. If you somehow ended up with a prf : Void, something is wrong and you have a contradiction.

OCaml use signature defined outside functor to limit visibility into produced module

I'm trying to write a functor that takes a pair of ordered things and produces another ordered thing (with ordering defined lexicographically).
However, I want the resulting "ordered type" to be abstract, rather than an OCaml tuple.
This is easy enough to do with an inline/anonymous signature.
(* orderedPairSetInlineSig.ml *)
module type ORDERED_TYPE = sig
type t
val compare : t -> t -> int
end
module MakeOrderedPairSet (X : ORDERED_TYPE) :
sig
type t
val get_fst : t -> X.t
val get_snd : t -> X.t
val make : X.t -> X.t -> t
val compare : t -> t -> int
end = struct
type t = X.t * X.t
let combine_comparisons fst snd =
if fst = 0 then snd else fst
let compare (x, y) (a, b) =
let cmp = X.compare x a in
let cmp' = X.compare y b in
combine_comparisons cmp cmp'
let get_fst ((x, y) : t) = x
let get_snd ((x, y) : t) = y
let make x y = (x, y)
end
I want to give my anonymous signature a name like ORDERED_PAIR_SET_TYPE and move it outside the definition of MakeOrderedPairSet, like so (warning: not syntactically valid) :
(* orderedPairSet.ml *)
module type ORDERED_TYPE = sig
type t
val compare : t -> t -> int
end
module type ORDERED_PAIR_SET_TYPE = sig
type t
type el
val get_fst : t -> el
val get_snd : t -> el
val make : el -> el -> t
val compare : t -> t -> int
end
module MakeOrderedPairSet (X : ORDERED_TYPE) :
(ORDERED_PAIR_SET_TYPE with type el = X.t) = struct
type t = X.t * X.t
let combine_comparisons fst snd =
if fst = 0 then snd else fst
let compare (x, y) (a, b) =
let cmp = X.compare x a in
let cmp' = X.compare y b in
combine_comparisons cmp cmp'
let get_fst ((x, y) : t) = x
let get_snd ((x, y) : t) = y
let make x y = (x, y)
end
with el being an abstract type in the signature that I'm trying to bind to X.t inside the body of MakeOrderedPairSet.
However, I can't figure out how to fit everything together.
(ORDERED_PAIR_SET_TYPE with type el = X.t) is the most obvious way I can think of to say "give me a signature that's just like this one, but with an abstract type replaced with a concrete one (or differently-abstract in this case)". However, it isn't syntactically valid in this case (because of the parentheses). Taking the parentheses off does not result in a valid "module-language-level expression" either; I left it on because I think it makes my intent more obvious.
So ... how do you use a named signature to restrict the visibility into a [module produced by a functor]/[parameterized module]?
If you don't want to add el to the exports of the module then there are two ways:
Use a substitution constraint:
ORDERED_PAIR_SET_TYPE with type el := X.t
That will remove the specification of el from the signature.
Use a parameterised signature. Unfortunately, that is not expressible directly in OCaml, but requires a bit of extra functor gymnastics around the definition of your signature:
module SET_TYPE (X : ORDERED_TYPE) =
struct
module type S =
sig
type t
val get_fst : t -> X.el
val get_snd : t -> X.el
val make : X.el -> X.el -> t
val compare : t -> t -> int
end
end
With that you can write:
module MakeOrderedPairSet (X : ORDERED_TYPE) : SET_TYPE(X).S = ...

Evaluating `IO` Actions from REPL

Given:
*lecture2> :let x = (the (IO Int) (pure 42))
Looking at its type, what's the meaning of the MkFFI C_Types String String signature?
*lecture2> :t x
x : IO' (MkFFI C_Types String String) Int
I then attempted to evaluate x from the REPL:
*lecture2> :exec x
main:When checking argument value to function Prelude.Basics.the:
Type mismatch between
IO Int (Type of x)
and
Integer (Expected type)
Also, why doesn't 42 print out in the REPL?
Looking at its type, what's the meaning of the MkFFI C_Types String String signature?
The IO' type constructor is parametrised over the FFI that is available within it. It'll be different depending on e.g. the backend you want to target. Here you have access to the C FFI which is the default one IO picks.
You can find out about these things by using :doc in the REPL. E.g. :doc IO' yields:
Data type IO' : (lang : FFI) -> Type -> Type
The IO type, parameterised over the FFI that is available within it.
Constructors:
MkIO : (World -> PrimIO (WorldRes a)) -> IO' lang a
Also, why doesn't 42 print out in the REPL?
I don't know how :exec x is supposed to work but you can evaluate x in an interpreter by using :x x instead and that does yield a sensible output:
Idris> :x x
MkIO (\w => prim_io_pure 42) : IO' (MkFFI C_Types String String) Int

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.