Deriving Typeable and Data for GADTs? - ghc

Using:
{-# LANGUAGE GADTs #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE DeriveDataTypeable #-}
And given the following datatype:
data Event a where
PureE :: a -> Event a
MapE :: (a -> b) -> Event a -> Event b
deriving instance Typeable Event
deriving instance Data a => Data (Event a)
My goal is to use the uniplate package which requires the Data instance.
Is GHC able to derive Typeable and Data automatically? Since 7.8 GHC should be able to do so and afaik at least for Typeable it is mandatory.
I could probably write my own Data instance ... but why do if GHC can just derive it for me?

This seems to work with GHC 8.10.7:
{-# LANGUAGE GADTs #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE QuantifiedConstraints #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE DeriveDataTypeable #-}
import Data.Data
data Event a where
PureE :: a -> Event a
MapE :: (a -> b) -> Event a -> Event b
deriving instance Typeable Event
deriving instance (forall b. Data b) => Data (Event a)
The trick is the quantified constraint (forall b. Data b) => ..., which allows GHC to instantiate Data b for any type b on-demand. It's like a "local instance declaration."

Related

Is using a default method pointer valid Fortran? (IFort compiler bug)

I just want to know for sure if this is valid Fortran or if I've misunderstood some usage. Is the following code valid?
Module MathFxns
implicit none
Type A_T
procedure(DoStuff_F), nopass, pointer :: method => add
contains
End Type A_T
Abstract Interface
Function DoStuff_F(a, b) result(c)
integer, intent(in) :: a, b
integer :: c
End Function DoStuff_F
End Interface
contains
function add(a, b) result(c)
integer, intent(in) :: a, b
integer :: c
c = a + b
end function add
End Module MathFxns
program Main
use MathFxns
implicit none
type(A_T) :: math
print *, math%method(2, 5)
end program Main
I just had to track down a compiler bug, that was being caused by something I think is valid Fortran. I'd submit to the compiler team, but I don't have a way to replicate as it's buried pretty far down in the stack and down multiple libraries before it caused a compiler bug and it doesn't happen in every program that uses it.
Edit: I didn't mention it before because it is complicated to explain, but since there was some curiosity, I'll try.
The production code does work in some executables, but recently I implemented it in another project which caused a compiler bug. I'll try to make a pseudo code example to illustrate, but first is a description. In the production code I have a type that has a default procedure pointer to a function (just like above). An instance of that type is a field of an abstract type. That abstract type is extended by another abstract type, then in a subsequent library that type is extended by another abstract type, which is then extended by a concrete type in another library. Finally an executable makes use of that concrete type. The module that has an instance of the concrete type throws a compiler error.
In the production code, it is an ODE Solver, with functionality wrapped into an entity type that gets extended a few times before being implemented.
It took me 6 hours, but after commenting and uncommenting line after line, the cause of the error was shown to be the default procedure pointer in the type. Whether that is the actual error or not, I can't know, but removing the default pointer (and pointing in the construction subroutine) made the project work again.
!this is in the first static library project
Module Library1
implicit none
Type A_T
!more stuff
procedure(DoStuff_F), nopass, pointer :: method => add
contains
!more procedures
End Type A_T
Type, abstract :: B1_A
type(A_T) :: a
!more stuff and procedures
End Type B1_A
Type, extends(B1_A), abstract :: B2_A
!more stuff and procedures
End Type B2_A
Abstract Interface
Function DoStuff_F(a, b) result(c)
integer, intent(in) :: a, b
integer :: c
End Function DoStuff_F
End Interface
contains
function add(a, b) result(c)
integer, intent(in) :: a, b
integer :: c
c = a + b
end function add
End Module Library1
! this is in the second static library project
Module Library2
use Library1
implicit none
Type, extends(B2_A), abstract :: B3_A
!more stuff and procedures
End Type B3_A
End Module Library2
! this is in the third static library project
Module Library3
use Library2
implicit none
Type, extends(B3_A) :: C_T
!more stuff and procedures
End Type C_T
End Module Library3
!this is in a fourth executable project
program Main
use Library3
implicit none
type(C_T) :: math
print *, math%a%method(2, 5)
end program Main

How can I fake existential types in Isabelle/HOL?

Consider the following Isabelle/HOL definition of a simple process language:
typedecl channel
datatype process = Put channel char process | Get "char ⇒ process" | Stop
This languages supports sending and receiving of characters via channels.
Now I’d like to have typed channels. The channel type should have the type of values it can transport as a parameter:
typedecl 'a channel
The Put and Get data constructors should have the following (polymorphic) types:
Put :: "['a channel, 'a, process] ⇒ process"
Get :: "['a channel, 'a ⇒ process] ⇒ process"
However, this requires support for existential quantification in data types, which Isabelle/HOL doesn’t have.
I tried to fake existential quantification and came up with the following attempt:
typedecl put
axiomatization put :: "['a channel, 'a] ⇒ put" where
put_inject: "put a x = put b y ⟷ a = b ∧ x = y"
bnf_axiomatization 'r get
axiomatization get :: "['a channel, 'a ⇒ 'r] ⇒ 'r get" where
get_inject: "get a f = get b g ⟷ a = b ∧ f = g"
datatype process = Put put process | Get "process get" | Stop
Unfortunately, this results in the following error message:
Type definition with open dependencies, use "typedef (overloaded)" or enable configuration option "typedef_overloaded" in the context.
Type: process
Deps:
map_get(process.process_IITN_process
⇒ (process_pre_process_bdT + process_pre_process_bdT process_pre_process) set ⇒ bool,
(process_pre_process_bdT + process_pre_process_bdT process_pre_process) set ⇒ bool),
bd_get,
set_get(process.process_IITN_process
⇒ (process_pre_process_bdT + process_pre_process_bdT process_pre_process) set ⇒ bool)
The error(s) above occurred in typedef "process"
Is my attempt reasonable, and, if yes, how can I solve this problem? Is there a better solution?
Indeed, the axiom for get is inconsistent with the bnf_axiomatization. However, if you restrict yourself to countable types 'a, then such a type exists. As soon as you fix such a cardinality bound, you do not even have to restort to axiomatization. Existential types can then be emulated within HOL using encoding and decoding functions into/from a universal domain.
For example, for countable types, the natural numbers can be used as the universal domain. This has been used, e.g., in Imperative_HOL to model a heap that can store typed values, see the paper from 2008. Huffman has done something similar for HOLCF, Isabelle's domain theory library.
With such an encoding in place, you'd construct the datatype of processes using untyped channels and then create a type-safe view on the datatype using the encoding and decoding functions as necessary.

Isabelle/HOL: access interpretation in another locale

There's an Isabelle/HOL library that I want to build on with new definitions and proofs. The library defines locale2, which I'd like to build upon. Inside locale2, there's an interpretation of locale1.
To extend locale2 in a separate theory, I define locale3 = locale2. Inside locale3, however, I can't figure out how to access locale2's interpretation of locale1. How can I do that? (Am I even going about this in the right way at all?)
Below is an MWE. This is the library theory with the locale I want to extend:
theory ExistingLibrary
imports Main
begin
(* this is the locale with the function I want *)
locale locale1 = assumes True
begin
fun inc :: "nat ⇒ nat"
where "inc n = n + 1"
end
(* this is the locale that interprets the locale I want *)
locale locale2 = assumes True
begin
interpretation I: locale1
by unfold_locales auto
end
end
This is my extension theory. My attempt is at the bottom, causing an error:
theory MyExtension
imports ExistingLibrary
begin
locale locale3 = locale2
begin
definition x :: nat
where "x = I.inc 7" (* Undefined constant: "I.inc" *)
end
end
Interpretations inside a context last only until the end of the context. When the context is entered again, you have to repeat the interpretation to make the definitions and theorems available:
locale 3 = locale2 begin
interpretation I: locale1 <proof>
For this reason, I recommend to split the first interpretation step into two:
A lemma with a name that proves the goal of the interpretation step.
The interpretation command itself which can be proved by(rulelemma)
If you want the interpretation to take place whenever you open the locale and whenever you interpret the locale, then sublocale instead of interpretation might be better.

quotient_type warning "no map function"

When using the quotient_type command I get the following warning: "No map function defined for Example.A. This will cause problems later on".
Here is a minimal example to trigger the warning(tested with Isabelle2017).
theory Example
imports
Main
begin
datatype 'a A = B "'a A" | C
(*for map: map *) (* uncommenting doesn't fix the warning*)
quotient_type 'a Q = "'a A" / "op ="
by (rule identity_equivp)
end
So my questions are:
What is meant by a map function in this context (I only do know the concept of a map function in the context of functors in functional programming)?
What does it have to do with the datatype packages map functions, like one that would be generated by the commented line?
Which problems will one get later on?
The datatype command does not by default register the generated map function with the quotient package because there may be more general mappers (in case there are dead type variables). You therefore must do the functor declaration manually:
functor map_A
by(simp_all add: A.map_id0 A.map_comp o_def)
The mapper and its theorems are needed if you later want to lift definitions through the quotient type. This has been discussed on the Isabelle mailing list.

Understanding the API of multi-prompt delimited continuations

An API for multi-prompt delimited continuations is described in the paper Delimited Control in OCaml, Abstractly and Concretely System Description.
My question concerns the type of push_subcont : ('a,'b) subcont -> (unit -> 'a) -> 'b. Why is this type not ('a,'b) subcont -> 'a -> 'b? Furthermore, why is there a separate type for subconts: why not simply ('a,'b) subcont = 'a -> 'b? I'm almost certain there is a good reason for that, because Oleg makes things as elegant as possible (but not more elegant).
Thanks!
Why not ('a,'b) subcont -> 'a -> 'b?
I think it is for the same reason as for push_prompt -- which is easier to understand. push_prompt p (fun () -> e) is intuitively a form of try e with p: the prompt p is placed on the stack as a handler, and e runs under this handler. If you used push_prompt p e instead, a strict language would evaluate the arguments p and e first, and e would run and "raise exceptions" before the prompt is set.
push_subcont sk (fun () -> e) could have the same kind of problems: it is a kind, intuitively, of "restart the computation sk that was interrupted by an exception". It is important that e is run inside the context of the computation, rather than outside it, for example if it wishes to raise exceptions corresponding to handlers installed by sk.
Why not simply ('a,'b) subcont = 'a -> 'b?
That could be done if there was only one way to restart subcontinuations: they could be returned "pre-restarted", under the form of functions that, when applied, restarts with the given argument.
But that is not the case: there are push_subcont and push_delim_subcont, described at the end of the article, that have different semantics. The "caller" should choose which restart technique to use. They both need to access internal data of the subcontiuation, so they could not operate on the subcontinuation-as-function representation.

Resources