Evaluation of effectual functions giving unexpected results - effects

Title is fairly self explanatory. Using this paper as a reference, I have been working out how to properly use effects in Idris. Creating effectual functions seems straightforward, but the actual evaluation of the effectual functions is giving me results I do not expect. For context, if I have the following program:
h1 : Eff Nat [SYSTEM, RND]
h1 = do srand !time
pure (fromInteger !(rndInt 0 6))
h2 : Eff Nat [SYSTEM]
h2 = pure (fromInteger !time)
h3 : Eff Nat [RND]
h3 = do srand 123456789
pure (fromInteger !(rndInt 0 6))
runH : IO ()
runH = do
x <- run h1 -- <---- This one works fine
--let x = runPure h1 -- <---- This one does not work << !!!
y <- run h2 -- <---- This one works fine
--let y = runPure h2 -- <---- This one does not work << !!!
--z <- run h3 -- <---- This one works fine
let z = runPure h3 -- <---- This one works fine << ???
putStrLn $
"test 1 : " ++ show x ++ "\n" ++
"test 2 : " ++ show y ++ "\n" ++
"test 3 : " ++ show z
I would expect to be able to get actual values out of h1, h2, and h3 with runPure, but the compiler will only let me do this for h3. Both h1 and h2 will only compile if they are evaluated with run. The only real differences I see are a) functions with multiple effects cannot use runPure or b) the SYSTEM effect cannot use runPure. Could anyone explain to me why the code above behaves the way it does?
The full error if I choose the line let y = runPure h2 over y <- run h2:
When checking right hand side of runH with
expected type
IO ()
When checking argument env to function Effects.runPure:
Type mismatch between
Env m [] (Type of [])
and
Env id [SYSTEM] (Expected type)
Specifically:
Type mismatch between
[]
and
[SYSTEM]

Related

Similar record types in a list/array in purescript

Is there any way to do something like
first = {x:0}
second = {x:1,y:1}
both = [first, second]
such that both is inferred as {x::Int | r} or something like that?
I've tried a few things:
[{x:3}] :: Array(forall r. {x::Int|r}) -- nope
test = Nil :: List(forall r. {x::Int|r})
{x:1} : test -- nope
type X r = {x::Int | r}
test = Nil :: List(X) -- nope
test = Nil :: List(X())
{x:1} : test
{x:1, y:1} : test -- nope
Everything I can think of seems to tell me that combining records like this into a collection is not supported. Kind of like, a function can be polymorphic but a list cannot. Is that the correct interpretation? It reminds me a bit of the F# "value restriction" problem, though I thought that was just because of CLR restrictions whereas JS should not have that issue. But maybe it's unrelated.
Is there any way to declare the list/array to support this?
What you're looking for is "existential types", and PureScript just doesn't support those at the syntax level the way Haskell does. But you can roll your own :-)
One way to go is "data abstraction" - i.e. encode the data in terms of operations you'll want to perform on it. For example, let's say you'll want to get the value of x out of them at some point. In that case, make an array of these:
type RecordRep = Unit -> Int
toRecordRep :: forall r. { x :: Int | r } -> RecordRep
toRecordRep {x} _ = x
-- Construct the array using `toRecordRep`
test :: Array RecordRep
test = [ toRecordRep {x:1}, toRecordRep {x:1, y:1} ]
-- Later use the operation
allTheXs :: Array Int
allTheXs = test <#> \r -> r unit
If you have multiple such operations, you can always make a record of them:
type RecordRep =
{ getX :: Unit -> Int
, show :: Unit -> String
, toJavaScript :: Unit -> Foreign.Object
}
toRecordRep r =
{ getX: const r.x
, show: const $ show r.x
, toJavaScript: const $ unsafeCoerce r
}
(note the Unit arguments in every function - they're there for the laziness, assuming each operation could be expensive)
But if you really need the type machinery, you can do what I call "poor man's existential type". If you look closely, existential types are nothing more than "deferred" type checks - deferred to the point where you'll need to see the type. And what's a mechanism to defer something in an ML language? That's right - a function! :-)
newtype RecordRep = RecordRep (forall a. (forall r. {x::Int|r} -> a) -> a)
toRecordRep :: forall r. {x::Int|r} -> RecordRep
toRecordRep r = RecordRep \f -> f r
test :: Array RecordRep
test = [toRecordRep {x:1}, toRecordRep {x:1, y:1}]
allTheXs = test <#> \(RecordRep r) -> r _.x
The way this works is that RecordRep wraps a function, which takes another function, which is polymorphic in r - that is, if you're looking at a RecordRep, you must be prepared to give it a function that can work with any r. toRecordRep wraps the record in such a way that its precise type is not visible on the outside, but it will be used to instantiate the generic function, which you will eventually provide. In my example such function is _.x.
Note, however, that herein lies the problem: the row r is literally not known when you get to work with an element of the array, so you can't do anything with it. Like, at all. All you can do is get the x field, because its existence is hardcoded in the signatures, but besides the x - you just don't know. And that's by design: if you want to put anything into the array, you must be prepared to get anything out of it.
Now, if you do want to do something with the values after all, you'll have to explain that by constraining r, for example:
newtype RecordRep = RecordRep (forall a. (forall r. Show {x::Int|r} => {x::Int|r} -> a) -> a)
toRecordRep :: forall r. Show {x::Int|r} => {x::Int|r} -> RecordRep
toRecordRep r = RecordRep \f -> f r
test :: Array RecordRep
test = [toRecordRep {x:1}, toRecordRep {x:1, y:1}]
showAll = test <#> \(RecordRep r) -> r show
Passing the show function like this works, because we have constrained the row r in such a way that Show {x::Int|r} must exist, and therefore, applying show to {x::Int|r} must work. Repeat for your own type classes as needed.
And here's the interesting part: since type classes are implemented as dictionaries of functions, the two options described above are actually equivalent - in both cases you end up passing around a dictionary of functions, only in the first case it's explicit, but in the second case the compiler does it for you.
Incidentally, this is how Haskell language support for this works as well.
Folloing #FyodorSoikin answer based on "existential types" and what we can find in purescript-exists we can provide yet another solution.
Finally we will be able to build an Array of records which will be "isomorphic" to:
exists tail. Array { x :: Int | tail }
Let's start with type constructor which can be used to existentially quantify over a row type (type of kind #Type). We are not able to use Exists from purescript-exists here because PureScript has no kind polymorphism and original Exists is parameterized over Type.
newtype Exists f = Exists (forall a. f (a :: #Type))
We can follow and reimplement (<Ctrl-c><Ctrl-v> ;-)) definitions from Data.Exists and build a set of tools to work with such Exists values:
module Main where
import Prelude
import Unsafe.Coerce (unsafeCoerce)
import Data.Newtype (class Newtype, unwrap)
newtype Exists f = Exists (forall a. f (a :: #Type))
mkExists :: forall f a. f a -> Exists f
mkExists r = Exists (unsafeCoerce r :: forall a. f a)
runExists :: forall b f. (forall a. f a -> b) -> Exists f -> b
runExists g (Exists f) = g f
Using them we get the ability to build an Array of Records with "any" tail but we have to wrap any such a record type in a newtype before:
newtype R t = R { x :: Int | t }
derive instance newtypeRec :: Newtype (R t) _
Now we can build an Array using mkExists:
arr :: Array (Exists R)
arr = [ mkExists (R { x: 8, y : "test"}), mkExists (R { x: 9, z: 10}) ]
and process values using runExists:
x :: Array [ Int ]
x = map (runExists (unwrap >>> _.x)) arr

How can I hide a name in the REPL?

As stated in the answer to this question, the %hide directive allows one to make an existing name inaccessible:
import Data.String
%hide fib
%default total
fib : Nat -> Nat
fib n = loop n 0 1
where
loop : Nat -> Nat -> Nat -> Nat
loop Z a _ = a
loop (S k) a b = loop k b (a + b)
parseNat : String -> Maybe Nat
parseNat = map cast . parsePositive
response : String -> String
response s = case parseNat s of
Just n => "fib n = " ++ show (fib n)
Nothing => "n ∉ ℕ"
partial main : IO ()
main = repl "n = " ((++ "\n") . response)
This works fine in the code above:
*Main> :exec
n = 10
fib n = 55
However, it does not seem to carry over to the REPL:
*Main> fib 10
Can't disambiguate name: Main.fib, Prelude.Nat.fib
How can I cause the %hide directives from my code to carry over into the REPL?
I think you can't and the only way to invoke your function is to use its fully qualified name, e.g. Main.fib 10 would work.

Messing around with category theory

Motivation: I am attempting to study category theory while creating a Coq formalization of the ideas I find in whatever textbook I follow. In order to make this formalization as simple as possible, I figured I should identify objects with their identity arrow, so a category can be reduced to a set (class, type) of arrows X with a source mapping s:X->X, target mapping t:X->X, and composition mapping product : X -> X -> option X which is a partial mapping defined for t f = s g. Obviously the structure (X,s,t,product) should follow various properties. For the sake of clarity, I am spelling out the formalization I chose below, but there is no need to follow it I think in order to read my question:
Record Category {A:Type} : Type := category
{ source : A -> A
; target : A -> A
; product: A -> A -> option A
; proof_of_ss : forall f:A, source (source f) = source f
; proof_of_ts : forall f:A, target (source f) = source f
; proof_of_tt : forall f:A, target (target f) = target f
; proof_of_st : forall f:A, source (target f) = target f
; proof_of_dom: forall f g:A, target f = source g <-> product f g <> None
; proof_of_src: forall f g h:A, product f g = Some h -> source h = source f
; proof_of_tgt: forall f g h:A, product f g = Some h -> target h = target g
; proof_of_idl: forall a f:A,
a = source a ->
a = target a ->
a = source f ->
product a f = Some f
; proof_of_idr: forall a f:A,
a = source a ->
a = target a ->
a = target f ->
product f a = Some f
; proof_of_asc:
forall f g h fg gh:A,
product f g = Some fg ->
product g h = Some gh ->
product fg h = product f gh
}
.
I have no idea how practical this is and how far it will take me. I see this as an opportunity to learn category theory and Coq at the same time.
Problem: My first objective was to create a 'Category' which would resemble as much as possible the category Set. In a set theoretic framework, I would probably consider the class of triplets (a,b,f) where f is a map with domain a and range a subset of b. With this in mind I tried:
Record Arrow : Type := arrow
{ dom : Type
; cod : Type
; arr : dom -> cod
}
.
So that Arrow becomes my base type on which I could attempt building a structure of category. I start embedding Type into Arrow:
Definition id (a : Type) : Arrow := arrow a a (fun x => x).
which allows me to define the source and target mappings:
Definition domain (f:Arrow) : Arrow := id (dom f).
Definition codomain (f:Arrow) : Arrow := id (cod f).
Then I move on to defining a composition on Arrow:
Definition compose (f g: Arrow) : option Arrow :=
match f with
| arrow a b f' =>
match g with
| arrow b' c g' =>
match b with
| b' => Some (arrow a c (fun x => (g' (f' x))))
| _ => None
end
end
end.
However, this code is illegal as I get the error:
The term "f' x" has type "b" while it is expected to have type "b'".
Question: I have the feeling I am not going to get away with this, My using Type naively would take me to some sort of Russel paradox which Coq will not allow me to do. However, just in case, is there a way to define compose on Arrow?
Your encoding does not work in plain Coq because of the constructive nature of the theory: it is not possible to compare two sets for equality. If you absolutely want to follow this approach, Daniel's comment sketches a solution: you need to assume a strong classical principle to be able to check whether the endpoints of two arrows match, and then manipulate an equality proof to make Coq accept the definition.
Another approach is to have separate types for arrows and objects, and use type dependency to express the compatibility requirement on arrow endpoints. This definition requires only three axioms, and considerably simplifies the construction of categories:
Set Implicit Arguments.
Unset Strict Implicit.
Unset Printing Implicit Defensive.
Record category : Type := Category {
obj : Type;
hom : obj -> obj -> Type;
id : forall {X}, hom X X;
comp : forall X Y Z, hom X Y -> hom Y Z -> hom X Z;
(* Axioms *)
idL : forall X Y (f : hom X Y), comp id f = f;
idR : forall X Y (f : hom X Y), comp f id = f;
assoc : forall X Y Z W
(f : hom X Y) (g : hom Y Z) (h : hom Z W),
comp f (comp g h) = comp (comp f g) h
}.
We can now define the category of sets and ask Coq to automatically prove the axioms for us.
Require Import Coq.Program.Tactics.
Program Definition Sets : category := {|
obj := Type;
hom X Y := X -> Y;
id X := fun x => x;
comp X Y Z f g := fun x => g (f x)
|}.
(This does not lead to any circularity paradoxes, because of Coq's universe mechanism: Coq understands that the Type used in this definition is actually smaller than the one used to define category.)
This encoding is sometimes inconvenient due to the lack of extensionality in Coq's theory, because it prevents certain axioms from holding. Consider the category of groups, for example, where the morphisms are functions that commute with the group operations. A reasonable definition for these morphisms could be as follows (assuming that there is some type group representing groups, with * denotes multiplication and 1 denotes the neutral element).
Record group_morphism (X Y : group) : Type := {
mor : X -> Y;
mor_1 : mor 1 = 1;
mor_m : forall x1 x2, mor (x1 * x2) = mor x1 * mor x2
}.
The problem is that the properties mor_1 and mor_m interfere with the notion of equality for elements of group_morphism, making the proofs for associativity and identity that worked for Sets break. There are two solutions:
Adopt extra axioms into the theory so that the required properties still go through. In the above example, you would need proof irrelevance:
proof_irrelevance : forall (P : Prop) (p q : P), p = q.
Change the category axioms so that the identities are valid up to some equivalence relation specific to that category, instead of the plain Coq equality. This approach is followed here, for example.

How to destruct/generalize over Program's rewritten match statements

When using Program, match statements are rewritten into a "proof-passing" style. This makes evidence of the match available in the branches—which can be critical.
However, it also seems to make case analysis more difficult. For example:
Require Import ZArith.
Open Scope Z_scope.
Program Definition test (x:Z) : option (x <= 100) :=
match Z_le_gt_dec x 100 with
| left bound => Some _
| right bound => None
end.
Lemma test_gt_100 : forall x:Z, x > 100 -> test x = None.
Proof.
intros x bound.
unfold test.
At this point, one would normally destruct (Z_le_gt_dec x 100) and the proof is then easy. However, the rewritten match gives this context:
x : Z
bound : x > 100
============================
match
Z_le_gt_dec x 100 as x0
return (x0 = Z_le_gt_dec x 100 -> option (x <= 100))
with
| left bound0 =>
fun Heq_anonymous : left bound0 = Z_le_gt_dec x 100 =>
Some (test_obligation_1 x bound0 Heq_anonymous)
| right bound0 => fun _ : right bound0 = Z_le_gt_dec x 100 => None
end eq_refl = None
With this, the destruct fails:
Toplevel input, characters 20-48:
Error: Abstracting over the term "s" leads to a term
"fun s : {x <= 100} + {x > 100} =>
match s as x0 return (x0 = s -> option (x <= 100)) with
| left bound =>
fun Heq_anonymous : left bound = s =>
Some (test_obligation_1 x bound Heq_anonymous)
| right bound => fun _ : right bound = s => None
end eq_refl = None" which is ill-typed.
Going more slowly and trying just to generalize (Z_le_gt_dec x 100) shows why:
Toplevel input, characters 0-30:
Error: Illegal application (Type Error):
The term "test_obligation_1" of type
"forall x : Z,
let filtered_var := Z_le_gt_dec x 100 in
forall bound : x <= 100, left bound = filtered_var -> x <= 100"
cannot be applied to the terms
"x" : "Z"
"bound0" : "x <= 100"
"Heq_anonymous" : "left bound0 = s"
The 3rd term has type "left bound0 = s" which should be coercible to
"left bound0 = Z_le_gt_dec x 100".
While that makes some sense, I'm at a loss about what to do about it.
(I've put this in collacoq if it's helpful. Don't forget to execute just the Comment line at first and then wait until all the libraries have loaded before importing ZArith.)
The problem here is that you depend on a specific equality term, abstracting over it should allow you to proceed. (It is is general good practice to state lemmas that are independent of proofs).
Here's your example, using ssreflect's rewrite. Sorry, I was unable to instruct Coq's one to do the proper pattern selection.
Comments "pkgs: coq-reals".
From mathcomp Require Import ssreflect.
Require Import Coq.ZArith.ZArith.
Open Scope Z_scope.
Program Definition test (x:Z) : option (x <= 100) :=
match Z_le_gt_dec x 100 with
| left bound => Some _
| right bound => None
end.
Lemma test_gt_100 : forall x:Z, x > 100 -> test x = None.
Proof.
intros x hb; unfold test.
assert (Z_le_gt_dec x 100 = right hb) as Hz. admit.
move: eq_refl; rewrite {1 3}Hz.
done.
[Also at https://x80.org/collacoq/xareboqura.coq ]
Best regards, E.
EDIT: A bit more detail: At the beginning, the argument of the match is eq_refl : forall x, x = x which is ok as the function inside the match expects a term of type Z.le .... = Z.le ..... However, when performing the rewrite, the type in the match annotation will become of the form Z_le ... = right ..., but if argument is still eq_refl this will result in a badly typed term, as eq_refl can never be typed as Z.le ... = right ...!
Thus, we modify our goal so that the proof for the equality doesn't necessarily have to be eq_refl, then we rewrite.
Why the proof was done with eq_refl in the first place? This is usually done to have good reduction behavior in the presence of equality proofs.
It would be interesting to add proof-irrelevance support to Program thou. (I ignore if there's already some).

Using List remove function

I'm trying to use the list remove function in Coq standard library but it asks for a bizarre typing and I don't know how to solve.
The function I'm implementing is to make a list of free variables in a lambda term as follows:
Fixpoint fv (t : trm) : vars :=
match t with
| Var v => [v]
| App t1 t2 => (fv t1) ++ (fv t2)
| Abs x t' => remove x (fv t')
end.
And it gives me the following error:
Error: In environment
fv : trm -> vars
t : trm
x : nat
t' : trm
The term "x" has type "nat" while it is expected to have type
"forall x0 y : ?171, {x0 = y} + {x0 <> y}".
I'm pretty sure there is something to do with that hyphotesis thing in the definition of the remove function. I have no idea how to deal with it though, any helps?
remove is defined in a context containing:
Hypothesis eq_dec : forall x y : A, {x = y}+{x <> y}.
The function removes takes this as a first argument (which you can see by doing Print remove.)
This hypothesis is a function deciding equality of elements of the type in your list. In your case, you will have to provide a function to decide equality of var (which seems to be nat, so there is probably such a function in the standard library too).
If you do not know the "{p} + {q}" notation, you can look it up here:
http://coq.inria.fr/library/Coq.Init.Specif.html#sumbool