Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Discussion for proposal 2020-001 (Addition of the Universal module) #27

Open
JohnReppy opened this issue Apr 22, 2020 · 9 comments
Open

Comments

@JohnReppy
Copy link
Contributor

No description provided.

@JohnReppy
Copy link
Contributor Author

JohnReppy commented Apr 22, 2020

This issue is for discussion of proposal 2020-001 (Addition of the Universal module).

@MatthewFluet
Copy link

In addition to a structure Universal : UNIVERSAL, perhaps it would be useful to have a functor MkUniversal() :> UNIVERSAL.

Just as it can be awkward to use the single exn type for all of one's universal type needs, it could be awkward to use the single Universal.universal type.

Also, as noted in the proposal, native compiler support might enable more efficient implementations. This might extend to more efficiently supporting separate universal types.

In any case, functor MkUniversal() :> UNIVERSAL = Universal would suffice as a default implementation.

@RobertHarper
Copy link
Contributor

RobertHarper commented Apr 23, 2020 via email

@JohnReppy
Copy link
Contributor Author

The arguments in favor of the Universal module are that it is more convenient to program with than using dynamic exceptions and that an implementation could provide a more efficient implementation than one gets from exceptions.

The name was chosen because "Universal" is what Poly/ML calls it. Since a subgoal is to make it easier to port code across implementations, so preserving the existing name is beneficial.

@dmacqueen
Copy link

dmacqueen commented Apr 23, 2020 via email

@ratmice
Copy link

ratmice commented Apr 23, 2020

Something always bothers me about these sorts of structures, which is the completeness of it,
If one can call tagProject, one can also call tagInject, Similar in a way to exception in that currently there isn't a mechanism for having a destructurable/handled execption which cannot then be rethrown again.

Any opinions on adding another subTag or equivalent type to the module which allows projection but not injection?

type 'a subTag

val derive_subtag: 'a tag -> 'a subTag;
val subtagIs: 'a subTag -> universal -> bool
val subtagProject: 'a subTag -> universal -> 'a 

Such that then given a subtag, one only has the right types to project out of a universal, without necessarily being able to project into them.

Edit: Not that i'm smitten with the name subTag, perhaps a better name might be weak_tag?
Edit: I'm not sure it's obvious what I intend 'a subTag to be here, essentially an opaque alias for 'a tag.

so we'd have

sig
type 'a tag;
type 'a subTag;
...
end

and

struct
type 'a tag = ...
type 'a subTag = 'a tag;
...

So derive_subtag is the identity function, and subtagIs and subtagProject are just their tag* variations with on a type with no inject.

@dmacqueen
Copy link

dmacqueen commented Apr 24, 2020 via email

@ratmice
Copy link

ratmice commented Apr 24, 2020

@dmacqueen that would work too, is there any interest/objections in including a signature as such?

Or is it something one is expected to know can be done and declare the signature separately in their own program using via structural subtyping?

The only real reason I did it in addition rather than as a structural subtype, is because reading the types, one gets implication that both are available and one is weaker than the other. I wouldn't think there is another difference.

So, to try that mechanism instead it'd be something like:
signature WEAK_UNIVERSAL

type universal

type 'a tag

val tag : unit -> 'a tag
val tagIs : 'a tag -> universal -> bool
val tagProject : 'a tag -> universal -> 'a

we could then perhaps add a function to UNIVERSAL, and Weak structure?

structure WeakUniversal: WEAK_UNIVERSAL
val weaken: universal -> WeakUniversal.universal
val weaken_tag: 'a tag -> 'a WeakUniversal.tag

That would preserve the discoverability aspect of it?
Edit: I guess rather than theabove what you were thinking was more like functor WeakenUniversal(it:UNIVERSAL) : WEAK_UNIVERSAL?

@YawarRaza7349
Copy link

@ratmice, in your second comment, you created a type WeakUniversal.universe distinct from universe. But in your first comment, subTags are used on the original universe type instead, which is the correct approach. So this is what the functor you mention in your last edit should look like:

functor ViewTags (U : UNIVERSAL) :> sig
  type 'a tag
  val viewTagOf : 'a U.tag -> 'a tag
  val tagIs : 'a tag -> U.universal -> bool
  val tagProject : 'a tag -> U.universal -> 'a
end

And why not also provide the dual notion?:

functor CreationTags (U : UNIVERSAL) :> sig
  type 'a tag
  val creationTagOf : 'a U.tag -> 'a tag
  val tagInject : 'a tag -> 'a -> U.universal
end

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants