I think backticks syntax makes sense for the Haskell since it has function
application via space, but for Elixir it hurts readability with no (visible
to me) benefits.
Calling non-guard-safe function as the guard-safe operators doesn't feel
like a good thing: we remove valuable hint about function property in our
code.
– Aleksei
On Thursday, August 11, 2016 at 8:51:47 AM UTC+2, Wiebe-Marten Wijnja wrote:
>
> Thank you for your replies!
>
> Indeed, the word 'guard' is missing from that sentence: The fact that
> Erlang only allows certain BIFs inside guard clauses, and therefore Elixir
> discouraging the overriding of operators that will not work in them.
>
> This suggestion is not at all meant as a replacement for the pipeline
> operator |>.
> The pipeline operator is built to accomodate the need to pass a single,
> most important, subject through a sequence of functions.
> These functions that work on a single, most important subject, can be
> described as 'Take the left-hand side, and perform the action outlined by
> the rest of the parameters'.
>
>
> However, the functions in the cases outlined above (arithmetic,
> comparisons, access, combinatorial, and there are probably more), it feels
> very weird, very unnatural to use the pipeline operator.
> These functions do not work on a single most important subject. Both the
> left-hand side and the right-hand side are equally important.
> These can be described as 'Take the left-hand side and the right-hand
> side, and perform the action ontlined by the name of the operation.'
>
> Using these binary (arity-2) functions with the pipeline operator feels
> strange and distracts from what is going on:
> a |> div(b)
> x |> lt?(y)
> {1,2,3,4} |> elem(2)
> %{foo: 1} |> Map.merge(%{bar: 2}) |> Map.merge(%{baz:3})
>
> The pipeline operator also stops to be useful in the case that we want to
> expand on the second argument of something:
>
> Observe that
> Decimal.add(decimal_a, Decimal.div(decimal_b, Decimal.new(2)))
> which the new syntax would let you write as
> decimal_a `Decimal.add` (decimal_b `Decimal.div` Decimal.new(2))
> was rewritten by Allen Madsen with the pipeline operator to
> decimal_b |> Decimal.div(Decimal.new(2)) |> Decimal.add(decimal_a)
> which swaps the order of parameters passed into `Decimal.add`. For
> addition this is not a problem, but take a non-reflexive operation like
> subtraction:
>
> Decimal.sub(decimal_a,Decimal.div(decimal_b, Decimal.new(2)))
> When using the pipeline operator, this would mean creating a call
> structure in this way:
> Decimal.sub(decimal_a, decimal_b |> Decimal.div(Decimal.new(2)))
> which would definitely be less readable than:
> decimal_a `Decimal.sub` (decimal_b `Decimal.div` Decimal.new(2))
>
>
> What I am trying to get at, is that the new syntax lets you write binary
> functions in the same location as the guard-safe operators, which will make
> user-defined structs feel more integrated with the language.
> If you can do
> a > b
> when a and b are built-in types, but are forced to use
> lg?(a, b)
> or
> a |> lg?(b)
> when having custom data types, I am not very happy.
> But if I can use
> a `lg?` b
> , I am. The semantics of the comparison are kept intact.
>
>
> ~Wiebe-Marten/Qqwy
>
>
>
>
> On Thursday, August 11, 2016 at 2:12:07 AM UTC+2, Ben Wilson wrote:
>>
>> I agree, this suggestion reads like the |> does not exist.
>>
>> I'm also not clear on what is meant by "One of the more longstanding
>> problems in Elixir is the fact that there is a difference between how code
>> is executed inside clauses and outside." What is a clause?
>>
>> On Wednesday, August 10, 2016 at 7:48:39 PM UTC-4, Allen Madsen wrote:
>>>
>>> In my opinion, the pipeline operator already solves this problem. I
>>> would rewrite some of your examples as follows:
>>>
>>> decimal_b |> Decimal.div(Decimal.new(2)) |> Decimal.add(decimal_a)
>>> Timex.today |> Timex.shift(days: 1) |> Timex.before?(Timex.today)
>>> a |> div(b)
>>> Allen Madsen
>>> http://www.allenmadsen.com
>>>
>>>
>>> On Wed, Aug 10, 2016 at 6:17 PM, Wiebe-Marten Wijnja
>>> <[email protected]> wrote:
>>> > One of the more longstanding problems in Elixir is the fact that there
>>> is a
>>> > difference between how code is executed inside clauses and outside.
>>> >
>>> > The choice was made to only define infix operators for the kinds of
>>> > operations that are guard-safe, so it is not confusing as to when you
>>> are
>>> > and when you are not allowed to use these infix operators.
>>> >
>>> > There is another problem that operators have: They are very cryptic.
>>> The
>>> > only way to know what an operator does, is if you've read its
>>> definition,
>>> > and still remember it. (Could you guess what `<|>`, `|^|` and `~?=` do
>>> in
>>> > Haskell?)
>>> >
>>> > Names of functions, on the other hand, are self-describing (as long as
>>> they
>>> > are named well, of course), so you instantly see what a piece of code
>>> does.
>>> >
>>> >
>>> > However, there are many operations that take two equally-important
>>> > arguments, which are much more natural to write in an infix-style than
>>> in a
>>> > prefix-style, as this is also the direction in which we 'think' them
>>> in.
>>> >
>>> > Some common examples include:
>>> > - Arithmetic operations like `+`, `-`, `*`, `/`, `div`, `mod`, `pow`.
>>> > - Comparison operations like `>`, `<=`, `!=`, `match?`,
>>> `MapSet.subset?`,
>>> > `lt?`, `gte?`, `neq?`.
>>> > - Access-based operations like the Access Protocol's `arr[x]`, `elem`,
>>> > `put_in`, `List.delete`.
>>> > - Operations that combine two structures, like `|`, `Map.merge`,
>>> > `MapSet.intersection`.
>>> >
>>> >
>>> > Because it is discouraged to override the infix operators for
>>> operations
>>> > that are not (and often cannot be) guard-safe, it feels a little
>>> 'clunky' to
>>> > use custom data structures, as we're forced to do things like:
>>> > Decimal.add(decimal_a, Decimal.div(decimal_b, Decimal.new(2))
>>> >
>>> > Timex.before?(Timex.shift(Timex.today, days: 1), Timex.today)
>>> >
>>> >
>>> >
>>> > As Guy Steele said in his marvelous talk 'Growing a Language': "When
>>> faced
>>> > with this, programmers that are used to performing addition using a
>>> plus
>>> > sign, quetch". (It is one of the most amazing talks I've ever seen, by
>>> the
>>> > way. I totally recommend tha you watch it right now.)
>>> >
>>> > If there were a way to use an infix notation for non-operators, users
>>> could
>>> > instead improve on the language in a "smooth and clean" way.
>>> >
>>> >
>>> > Taking inspiration from Haskell's syntax, I realized that there is a
>>> way to
>>> > circumvent this problem:
>>> >
>>> > My proposal: Introduce backtick-syntax to use arity-2 functions
>>> inline.
>>> >
>>> > - Functions (and macros) with arity 2, can be written as
>>> > a `div` b
>>> > This is rewritten during compilation into
>>> > div(a, b)
>>> >
>>> >
>>> > Some more examples:
>>> > users[1][:name] `put_in` "José"
>>> > {x, _} `match?` foo
>>> > {1, 2, 3} `elem` 2
>>> >
>>> >
>>> > - Both local and remote functions can be called this way. The
>>> following is
>>> > thus also valid:
>>> > %{a: 1, b: 2} `Map.merge` %{c: 3, d: 4}
>>> > ["foo", "bar", "baz"] `List.delete` "bar"
>>> >
>>> >
>>> > - This rewriting happens from left-to-right,(left-associative) so:
>>> > import Map
>>> > a `merge` b `merge` c
>>> > is rewritten into:
>>> > merge(merge(a, b), c)
>>> >
>>> >
>>> > As far as I know, this is completely backwards-compatible: Backticks
>>> are not
>>> > allowed inside Elixir syntax right now.
>>> > The only place where they are 'used' is inside documentation strings,
>>> to
>>> > delimit in-line markdown code snippets.
>>> > This is not a problem, however; To create an in-line code snippet that
>>> > allows backticks to be used internally, one can simply delimit it with
>>> two
>>> > backticks. This is already used inside the documentation of Elixir
>>> itself,
>>> > such as on the page about writing documentation.
>>> >
>>> > -------
>>> >
>>> >
>>> > Adding infix backtick-syntax is better than the current situation,
>>> because:
>>> > - It allows a more natural syntax for binary operations, making the
>>> language
>>> > more readable.
>>> > - It makes custom data structures feel more integrated into the
>>> language.
>>> >
>>> > This solution is better than 'just adding more possible operators'
>>> because:
>>> > - It keeps it very clear what is allowed inside guard-clauses and what
>>> > isn't.
>>> > - It is explicit what an operation does, as names are self-describing
>>> while
>>> > operator symbols are not.
>>> >
>>> >
>>> > --------
>>> >
>>> >
>>> > Please, tell me what you think. :-)
>>> >
>>> >
>>> > ~Wiebe-Marten/Qqwy
>>> >
>>> > --
>>> > You received this message because you are subscribed to the Google
>>> Groups
>>> > "elixir-lang-core" group.
>>> > To unsubscribe from this group and stop receiving emails from it, send
>>> an
>>> > email to [email protected].
>>> > To view this discussion on the web visit
>>> >
>>> https://groups.google.com/d/msgid/elixir-lang-core/2d7507ef-9ea3-4d0e-809b-8c1c674eb951%40googlegroups.com.
>>>
>>>
>>> > For more options, visit https://groups.google.com/d/optout.
>>>
>>
--
You received this message because you are subscribed to the Google Groups
"elixir-lang-core" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To view this discussion on the web visit
https://groups.google.com/d/msgid/elixir-lang-core/e84c7377-4bef-458d-9a39-0ef2580533ef%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.