Delfigamer
> Ты уверен?
Да, это же просто отступ на 1 уровень вверх в AST. А operator.> это просто модификатор AST на этапе его построения.
> Казалось бы, что может пойти не так?
Хорошее замечание, но преимуществ, имхо, это не перевешивает.
=A=L=X=
> преимуществ
Каких?
obj1.>func1.>func2.>func3( _$$, _$ ) - это не преимущество, это пердимонокль.
Delfigamer
> это не преимущество, это пердимонокль.
>
Спасибо, ваше мнение нам всем очень важно.
entryway
> https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference…
> line_operator
Интересно, что все дружно взялись писать оператор как |>. Общий предок? В пропозале от C++ явно сперва проговаривается про operator|.
Имхо, .> тут более естественна, т.к. продолжает семантику цепочечных вызовов ООП, а | в оригинале в сишных языках наоборот обрывает вычисление на первом же труфи.
=A=L=X=
> Интересно, что все дружно взялись писать оператор как |>. Общий предок?
4.3 Prior Art (in C++ and elsewhere)
The particular form of the operator this paper is proposing comes from the Elixir programming language, where it is known as the pipe operator [elixir.pipe]. Its semantics are the same as are being proposed here. From the docs:
iex> "Elixir rocks" |> String.upcase() |> String.split()
["ELIXIR", "ROCKS"]
F# [f-sharp.pipe], Julia [julia.pipe], Elm [elm.pipe], and OCaml also have an operator named |>
entryway
> F# Julia Elm OCaml
Ну понятно - через функциональщину и пролезло. Ожидаемо, ожидаемо...
А в хаскелле $ или типа того, не помню уже.
Там уже выбор символа мог быть от балды конечно.
=A=L=X=
> А в хаскелле $ или типа того, не помню уже.
Чтобы функция была справа - это амперсанд.
А если ещё нужны побочные эффекты - то это байнд.
(&) :: a -> (a -> b) -> b
x & f = f x
(>>=) :: (Monad m) => m a -> (a -> m b) -> m b
a :: [Text.Text]
a = "lorem ipsum" & Text.map Char.toUpper & Text.words
b :: IO ()
b = pure [10, 20, 30] >>= mapM (\i -> print i >> pure (i*2)) >>= print
main = do
print a
b
{-
["LOREM","IPSUM"]
10
20
30
[20,40,60]
-}Но обычно в ситуациях, аналогичных ОПу, используют оператор композиции (.), а в нём порядок получается справа налево. Люди хавают.
Да, и злоупотребление этими операторами в ущерб читаемости - это говнокод.
Вообще меня поднапрягло сходу придумать пример который бы рационально использует ссылку на предыдущий плейсхолдер (т.е. _$$), но помозговав родил такое:
(str1+str2).>substr( 0,1).>replace( _$$,_$,"")
Т.е. тут мы берём первый символ (как строку) выражения и потом удаляем его из... выражения же. Здесь как раз надо сослаться на результат из предыдущего вызова функции.
Соглашусь, что непривычно и модифицировать такой код надо с осторожностью, что подводит к следующей эволюции концепта: внедрить в него точки именования результатов для ссылок назад.
Предлагаю расширить тогда оператор .> фигурностями вида .{name}> - при таком использовании выражение слева заимеет псевдоним name который можно использовать справа:
(str1 + str2).{_sum}>substr( 0, 1).>replace( _sum, _$, "")
Тут как бы результат "протягивается" через псевдоним _sum и его можно использовать правее.
Нагляднее, конечно, выписывать такой код в столбец:
(str1 + str2).{_sum}> substr( 0, 1).> replace( _sum, _$, "")
=A=L=X=
> А добавив свою функцию some( str ) мы просто уже не можем её воткнуть в эту
> последовательность таким же выпрямленным образом. Получится опять что-то
> неприятное вида:
>
> ... some( str.split( "," ).join( ";" ) ).replace( "\n", " " ) ...
Я как говорил ранее в JS это решается добавлением своего прототипа
String.prototype.some = function(){}
и код становиться по прежнему красивым
str.split( "," ).join( ";" ).some().replace( "\n", " " )
Так. Пока ходил в магазин придумал идеальный, кмк, синтаксис. .{name}> из выше всё-таки плохо читаемо до уродливости.
Кроме того оно вводит 2 новых лексемы .{ и }> к имеющейся новой одной .> и это тоже переголова.
На самом деле пусть оператор .> работает как выше описано, а к нему мы добавим еще один новый оператор: |> . Он как раз совпадает с общепринятым, но отличается по смыслу.
Оператор |> в выражении вводит в точке своей встречи идентификатор записанный справа от себя и приравнивает его выражению записанному слева от себя: expr |> name
При этом результатом является само выражение - здесь как бы просто вводится имя для всего написанного справа, при этом оно становится видно до конца выражения справа от оператора.
Таким образом сочетая .> и |> можно как раз конструировать легко читаемые "выпрямленные" линейные выражения.
Перепишем последнее мной написанное, получается намного лучше:
(str1 + str2) |> _sum .> substr( 0, 1) .> replace( _sum, _$, "")
или
(str1 + str2) |> _sum .> substr( 0, 1) .> replace( _sum, _$, "")
NetSpider
> и код становиться по прежнему красивым
...но глюкодромным.
Как раз из обсуждения у тебя в теме эта и родилась - как предложение сделать всё красиво. И без глюкобажия и без многословия.
=A=L=X=
Да почему глюкодромным-то?
Какая-то патологическая неприязнь расширять не свои объекты. Словно позвонили неизвестные по телефону, сказали "расширь чужой объект" и деньги с карточки списали. Шизофрения же.
Случайно попасть в пространство имен новой версии языка - мизерное. Ну раз прям боишься, ну добавь свой префикс к имени типа myReplaceAll. Как вы любите создать проблем на ровном месте, я удивляюсь
=A=L=X=
> Т.е. тут мы берём первый символ (как строку) выражения и потом удаляем его
> из... выражения же. Здесь как раз надо сослаться на результат из предыдущего
> вызова функции.
Вот тут как раз и плавно приближаемся почему this в JS реализован так как реализован.
В JS в частности this является тем объектом в контексте которого произошел вызов метода или функции. Выглядит примерно так:
str -> this -> split( "," ) -> this -> join( ";" )
Поэтому в других языках вы не сможете реализовать такую возможность, потому что this используется как указатель на текущий объект. Даже если мы присобачим выдуманный оператор ".>" Получится:
str.>split( "," ).>join( ";" )
А куда будет ссылаться this в таком случае метода join? Сам на себя! Он не получит никаких данных по цепочке.
NetSpider
> Да почему глюкодромным-то?
Я устал это объяснять уже десятый раз уже в той теме поэтому в этой обсуждение этого вопроса проводить не буду.
> А куда будет ссылаться this в таком случае метода join? Сам на себя! Он не получит никаких данных по цепочке.
В языке типа C++ join это свободная функция и "this" это просто первый параметр. Всё просто. Это не вмешательство внутрь объекта, а просто его использование в функции в синтаксисе похожем на вызов метода, но это не вызов метода. Конкретный пример как это выглядит есть во втором комментарии этой темы.
При этом если хочется в этом стиле передать параметр в метод существующего объекта, то это тоже не запрещено, например:
str1 .> (str2.replace)( "" )
Это эквивалентно
str2.replace(str1, "" )
Т.е. this у replace будет str2, а в параметры пойдут str1 и "". Скобки нужны чтобы callable объект правильно вычленялся.
=A=L=X=
> _$$
А если вместо этого попробовать придумать синтаксис для явного (но, естественно, опционального) именования результатов каждого этапа цепочки?
Тут сразу еще одно замечание - в первопосте было раскритиковано введение промежуточных переменных в императивном коде - но ведь они по факту за кулисами ничего не меняют, в любом случае промежуточное значение живет некоторое время в стеке, другой вопрос - именовано это промежуточное значение или анонимно.
Так может быть нет ничего страшного в том, чтоб именовать промежуточные результаты, но только для цепочечного случая придумать синтаксис такой, чтоб время жизни и область видимости не торчали до самого конца блока, а ограничивались только цепочкой?
UPD. А, Алекс уже придумал, оказывается, не дочитал :)