Skip to content

Postfix projections#343

Merged
gallais merged 12 commits intoidris-lang:masterfrom
ziman:postfix-app
Jul 7, 2020
Merged

Postfix projections#343
gallais merged 12 commits intoidris-lang:masterfrom
ziman:postfix-app

Conversation

@ziman
Copy link
Collaborator

@ziman ziman commented Jun 20, 2020

This is a port of the original PR.

Included changes:

  • .proj is now allowed for any identifier proj, not only record projections.
  • .(complex expression), which works just like .proj but you can have an arbitrary expression on the RHS. This is feature-gated by %language PostfixProjections.
  • The special RF constructor for names of the form .recordField is gone; it does not make much sense anymore with this more general syntax.

Even without %language PostfixProjections enabled, this patch expands the set of accepted programs by allowing non-record-projections in .proj. I'm not sure how to feature-gate this easily but maybe it's okay as it is.

@ziman
Copy link
Collaborator Author

ziman commented Jun 21, 2020

I added a patch that changes the following:

  • Bare .proj without a preceding operand is no longer valid syntax, so f $ .proj no longer parses. You have to write f $ (.proj) or f (.proj) or f proj.
  • We now support projection sections: (.proj1.proj2 y z) is equivalent to (\x => x.proj1.proj2 y z). This is feature-gated by %language PostfixProjections.

So you can say:

  • map (.add 4) [1,2,3]
  • map (.oopFoldl 0 (+)) [[1,2,3], [4,5,6]]

@gallais
Copy link
Member

gallais commented Jul 7, 2020

Are we happy with this PR? I am happy with it.
Just need a quick rebase & then we can merge it.

@ziman
Copy link
Collaborator Author

ziman commented Jul 7, 2020

I rebased it and fixed the tests. Let's hope the CI agrees, too.

@Russoul
Copy link
Contributor

Russoul commented Jul 12, 2020

@ziman expression x .f y .g z parses like (x .f) (y .g) z.
May it be (x .f y) .g z ?

Motivation:

ability to use 'standard', 'scala-like' function application syntax:
suppose:
map : m a -> (a -> b) -> m b
reduce : m a -> (a -> a -> a) -> a
then this would be possible:
list.map(\x => 2 * x).reduce(+) == reduce (map list (\x => 2 * x)) (+)
or
students.target("Peter").update(.expelled) == update (target students "Peter") (\s => expelled s)

but currently it is:
(list.map) ((\x => 2 * x).reduce(+)) == map list (reduce (\x => 2 * x) (+))
or
(students.target) (("Peter").update(.expelled))

@ziman
Copy link
Collaborator Author

ziman commented Jul 12, 2020

I can see where you're coming from but I think that the suggestion goes against the purpose of postfix projections, which is binding tighter than application. (Since you cannot define so tightly binding operators yourself, a change to the syntax was necessary.)

The suggestion would make f x.y p.q interpreted as q (y p (f x)) rather than f (y x) (q p), if I understand correctly, and you'd lose the ability to access record fields in applications, which was the motivation for postfix projections.

I think that what you suggest would be better achieved by borrowing infixl (&) : a -> (a -> b) -> b from Haskell. Then you could write list & map (2 *) & reduce (+). I think this should behave as you suggest, except that you'd write & instead of ..

Alternatively, you can currently write list.(map (2 *)).(reduce (+) 0).

@Russoul
Copy link
Contributor

Russoul commented Jul 12, 2020

@ziman yeah, gotcha

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants