Closed francescoagati closed 5 months ago
Thanks for the suggestions!
We'll probably add the |>
pipe operator at some point.
I don't think we'll add LiveScript's operators as functions, instead we have &
function syntax which covers a lot of that same need.
list.map &+1
people.map &.name
---
list.map($=>$+1)
people.map($=>$.name)
I also don't think we'll add -->
curried functions but I'm open to be convinced with examples.
We now have the pipe operator |>
, but I think we're still lacking in what are called placeholders in the TC39 proposal, which I think is a natural way to support partials/currying. Copying from https://github.com/DanielXMoore/Civet/pull/83#issuecomment-1364739339 :
I imagine it's really common to want to pass the piped value in as a first argument to a function, with other arguments given explicitly. What we want is shorthand for ($) => func($, foo, bar)
.
func((&), foo, bar)
, where each extra layer of parens around &
pushes the function wrapper up a level.func(&&, foo, bar)
, where each additional &
pushes the function wrapper up a level.func(&, foo, bar)
in the context of the right-hand side of |>
(probably a bad idea?).func(%, foo, bar)
or various other notation that is specific to pipelining; for example, ^^
might mean the left-hand side of |>
(no matter how deep we are), or we could optionally add an identifier like |foo>
to mean "wrap the right-hand side in a function with single argument foo
). For example, |$> func($, foo, bar)
would be equivalent to |> ($) => func($, foo, bar)
.Not sure what's best, but it kind of highlights the limitation of the current &
notation... yet it feels like we're close.
I think using explicit arrow functions as a way to re-order arguments or specify a local alias is good. That way you can add type annotations and make use of destructuring and everything should compose fine. This way we can combine with existing language features rather than making special purpose syntaxes for every situation.
x + 1 |> ($) => $ * $
credentials
|> login
|> getUser
|> ({id}) => register id, 1
I have noticed the ->
is taken for the function declaration.
It could be great if it were for curried functions.
Just an example:
fun add(x::number, y::number)
x + y
// equals ๐
function add(x: number, y: number) {
return x + y
}
add := (x:: number, y:: number) => x + y
// equals ๐
const add = (x: number, y: number) => x + y
add := (x:: number, y:: number) -> x + y
// equals ๐
const add = curry((x: number, y: number) => x + y)
// ๐งadd can be called:
add(1, 2)
add(1)(2)
// usage
input := 4
// pipe version
input
|> add 3
|> subtract 2
|> console.log
// function composition
compute := compose(
console.log
minus 2
add 3
)
compute input
// prints ๐ 5
Or maybe we can use '>->' ?
Many monospaced fonts have that array in ligatures.
@sultan99 Thanks that's a great example for how curried functions can combine with the pipe operator.
I think using LiveScript's -->
or your suggestion of >->
for a curried function declaration is something we could add.
@STRd6, any of these can be!
>->
& -->
monolisa & fira fonts have them:
What about ~>
?
What about
~>
?
Ideally whichever we choose would have both ==>
and -->
versions to correspond to the two ES flavors of functions.
I have checked the ligatures, and we have all of them!
== === != !== > --> => ==> ~> >-> ๐
I think ==>
& -->
are the best:
add := (x:: number, y:: number) ==> x + y
// equals ๐
const add = curry((x: number, y: number) => x + y)
add := (x:: number, y:: number) --> x + y
// equals ๐
const add = curry(
function(x: number, y: number) {
return x + y
}
)
In the second example, we can use this
.
Not sure why but anyway:
add := (x:: number, y:: number) -->
console.log(@.name)
x + y
Guys, it would be sexy syntax!
toJson := res => res.toJson()
pick := (key:: keyof T, obj:: T) ==> obj[key]
id := 123
fetch 'api/users/:#{id}'
.then toJson
.catch pick 'message'
.finally console.log
If we're using the ==>
operator, why do we need the ::
instead of normal :
?
As for the compilation output, not sure you need a utility function, you could just compile it this way
add := (x:: number, y:: number) ==> x + y
const add = (x: number) => (y: number) => x + y
add := (x:: number, y:: number) --> x + y
const add = (x: number) => function (y: number) { return x + y }
I have seen ::
in the discord chat as a suggestion to use it for typing.
I'm not familiar with syntax yet and I'm still confusing proposals with real syntax.
Sorry...
@sultan99 The ::
is for https://github.com/DanielXMoore/Civet/discussions/126, where we plan to provide a more concise way to destructure and type parameters at the same time.
Not sure if this is the right ticket for what I'm after, let me know if not and I'll create a new ticket instead.
I use ramda a lot and I'm curious if civet could support a few things natively. Something I do a lot with ramda is create a function using pipe. For example:
const doTheThing = R.pipe(
R.pluck('myprop'),
R.map(R.toUpper)
)
console.log(doTheThing([{myprop: 'hello'}])) // outputs [HELLO]
My attempt at doing this with civet
input := [myprop: 'hello']
pluck := (prop) => .map .`${prop}`
// works
input
|> pluck 'myprop'
|> .map .toUpperCase()
|> console.log
// doesn't do what I want it to do
doTheThing := pluck 'myprop' |> .map .toUpperCase()
// doesn't work either, but in a different way
doTheThing2 := .map .myprop |> .map .toUpperCase()
console.log doTheThing2 input
doTheThing comes out as
const doTheThing = pluck("myprop").map(($3) =>
$3.toUpperCase()
);
// as the first thing in the pipe is a function I would have wanted
const doTheThing = ($) => pluck("myprop")($).map(($3) =>
$3.toUpperCase()
);
doTheThing2 comes out as
const doTheThing2 = (($4) =>
$4.map(($5) => $5.myprop)).map(($6) =>
$6.toUpperCase()
);
// I would have wanted (note one less paren after $5.myprop, it's added to the last line instead
const doTheThing2 = (($4) =>
$4.map(($5) => $5.myprop).map(($6) =>
$6.toUpperCase()
));
Or perhaps I'm just using it wrong, perhaps the pipe operator |>
is only intended to be used when there's a start value, and there's something like fp-ts flow operator that I'm missing? Pipe vs flow in fp-ts.
the operator works only on a start value, you are looking for a function composition operator (flow in fp-ts) which we discussed a bit in the Discord.
@kabo this might work but I agree that it would be nice to have a cleaner syntax for function composition kinds of things.
doTheThing := ($) => (pluck 'myprop' |> .map .toUpperCase())($)
ok, so I can go ahead and create a ticket for a function composition / flow operator?
@kabo Sounds good. I don't think we have another issue specifically for composition / flow yet. There are some discussions and maybe an issue that are related but we can link them in later.
Thanks for the detailed report and clear description!
I think
==>
&-->
are the best:
@sultan99 Agreed, out of thoseโฆ There is also =>>
and ->>
, which havenโt been mentioned, and I think visually express currying quite wellโฆ also have ligatures. cc: @STRd6 @edemaine
Closing this as:
f(x, ., y)
compiles to $ => f(x, $, y)
, especially useful in pipelines
%
. There are some limited cases not yet covered, like |> foo(a, bar(b, %))
. But we can revisit that in the future.
Livescript support piping partials and curry function. Should be nice have this in Civet