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

Make the argument n-ary constructor behave as a tuple #6455

Closed
vicuna opened this issue Jun 11, 2014 · 12 comments
Closed

Make the argument n-ary constructor behave as a tuple #6455

vicuna opened this issue Jun 11, 2014 · 12 comments

Comments

@vicuna
Copy link

vicuna commented Jun 11, 2014

Original bug ID: 6455
Reporter: @alainfrisch
Status: closed (set by @alainfrisch on 2015-11-12T14:38:05Z)
Resolution: won't fix
Priority: normal
Severity: feature
Category: typing
Monitored by: @diml @ygrek Bardou @jmeber @yallop @hcarty

Bug description

Since we use the tuple syntax for n-ary constructors:

type t = A of int * int

it would make sense to let the user manipulate the argument as a real tuple:

let f = function A x -> (x : int * int)
let g x = A x

In general, one needs to copy the constructor fields into a fresh tuple, or the opposite. (The case where the n-ary constructor has tag 0 could be optimized to avoid allocations in [f] and [g].)

One argument against this could be that this proposal hides an allocation when the tuple is extracted from the n-ary constructor. But this is not really different from extracting a float from a float record.

File attachments

@vicuna
Copy link
Author

vicuna commented Jun 11, 2014

Comment author: @mshinwell

Does it actually matter if the tuple has the "wrong" tag? (It isn't clear to me what we gain by insisting they have tag zero. Likewise for records, I suppose, if you think about the proposal to have records in constructor arguments.)

@vicuna
Copy link
Author

vicuna commented Jun 11, 2014

Comment author: @alainfrisch

@shinwell:

type t = A of int | B of int * int

let f = function B x -> x = (0, 0) | A -> false

If you want [f] to behave as expected, you need to ensure that the extracted tuple (x) has the tag 0.

@vicuna
Copy link
Author

vicuna commented Jun 11, 2014

Comment author: @mshinwell

Ah, that's true, we'll be stymied by the comparison code. That's unfortunate.

@vicuna
Copy link
Author

vicuna commented Jun 11, 2014

Comment author: ybarnoy

I'd be more interested in a function direction, similar to haskell:

type t = A of int | B of int * int

(A is of type int -> t, B is of type int -> int -> t)

which we could then curry, by writing for example let x = B 4

The cool thing is, that unlike haskell where they couldn't generalize this over to records properly, we can using labels:

type t = A of {x:int} | B of {x:int; y:int}

(A is of type x:int -> t, B is of type x:int -> y:int -> t

So maybe the proper way to do inline records in constructors is B ~x:3 ~y:2?

EDIT: of course we'd have to be backwards compatible, so the form A(3, 4) would feed the whole 'tuple' into A for the first example.

@vicuna
Copy link
Author

vicuna commented Jun 11, 2014

Comment author: @alainfrisch

I don't think it is a good direction to allow:

let x = B 4

after a definition such as:

type t = B of int * int

because we still need to support:

let x = B (1, 2)

Which type would you give to "fun x -> B x"?

Currying is very much at odds with the current syntax for n-ary constructors...

What could make sense is to consider a non-constant constructor as a well-typed functional value. I.e. B would have type (int * int) -> t. This is independent from both the current topic (and the one on inlined records), although it goes into the same direction of making similar syntax behave in a similar way (combining the two: "B (x, y)" would be interpreted as the application of the "B" function to a tuple argument).

@vicuna
Copy link
Author

vicuna commented Jun 11, 2014

Comment author: ybarnoy

OK that's a good point -- we can't really support currying syntax at the same time as tuple syntax. I wish we could just have a compiler switch to switch to a new constructor syntax, and leave tuple constructors in the past. We'd then use a pragma to switch the feature on per-file, and eventually deprecate the old way. I really like the way record-like constructors could map onto labels. Anyway, sorry for the tangent.

@vicuna
Copy link
Author

vicuna commented Jun 11, 2014

Comment author: Bardou

What about (B) or #B to mean "curried B"?

@vicuna
Copy link
Author

vicuna commented Nov 9, 2015

Comment author: @alainfrisch

Upload a small patch to implement the proposal in expressions (not patterns). The implementation strategy can lead to misleading error message (example in the patch). A better solution would involve a tighter integration with the type-checking logic.

@vicuna
Copy link
Author

vicuna commented Nov 9, 2015

Comment author: @alainfrisch

Uploaded a second version which improves the error messages at the cost of type-checking twice the argument of the constructor.

@vicuna
Copy link
Author

vicuna commented Nov 9, 2015

Comment author: @alainfrisch

Uploaded a third version which delays the expansion into the Typedtree->Lambda phase. This is better since it keeps the Typedtree AST more faithful to the original code. A simple optimization would be to avoid copying the tuple when the constructor has tag 0.

@vicuna
Copy link
Author

vicuna commented Nov 9, 2015

Comment author: @alainfrisch

Also implemented the pattern side. Time to switch to github:

https://github.com/alainfrisch/ocaml/tree/tuple_constructors

@vicuna
Copy link
Author

vicuna commented Nov 12, 2015

Comment author: @alainfrisch

See the discussion on Github.

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

No branches or pull requests

1 participant