Я почитал ваш постинг про язык J, и, похоже у нас с Вами существенное отличие в понимании того, что такое красивая программа или язык, а что нет. При условии конечно что весь постинг не был шуткой. Впрочем, он оказался хорошим поводом продемонстрировать силу language-oriented подхода.
Итак, в моем понимании Ваш пример написанный на языке J выглядит абсолютно ужасно.
Для меня критерий красоты программы это тогда когда она написана абсолютно ясно и максимально близко к тому как задача и ее решение формулировались бы у меня в голове или как бы я ее рассказал на естественном языке другому человеку. У Вас же восторг вызывает стремление написать программу как можно короче.
Давайте рассмотрим Ваш пример подробнее. Стоит задача - найти выпуклую оболочку для заданного множества точек на плоскости. По Вашим же словам:
Алгоритм этот заключается в том, чтобы
1. Отсортировать точки по углам, относительно самой левой из них (которая по определению принадлежит оболочке).
2. А потом, пройдя по образовавшемуся звездообразному контуру последовательно, начиная с левой точки,
2.1 удалить все, угол при которых (относительно внутренности многоугольника) выгнут наружу (>180ˆ).
Result: Те точки, что останутся, будут образовывать вогнутые углы, а значит оболочка получится выпуклой.
Я скопировал здесь Вашу программу, которая реализует этот алгоритм на J:
s =: ({. , }. /: 12"_ o. }. - {.) @ /:~ l =: 11"_ o. [: (* +)/ }. - {. rr =: (1"_ , (0"_ > 3: l\ ]) , 1"_) # ] hull =: [: rr^:_ s
А теперь я попробую написать как выглядела бы с моей точки зрения идеальная программа, реализующая этот же алгоритм.
Для написания этой программы я буду использовать язык подобный Java, расширенный языком работы с коллекциями (подобный язык в частности будет поставляться вместе с MPS) и зачатками языка манипулирующего точками на плоскости (или, возможно, вместо него - языка комплексных чисел)
Array ConvexHull(Collection points) { leftPoint = find in points by minimum of p.x sortedArray = leftPoint + create Array from points where element != leftPoint sorted by angleToXAxis(element-leftPoint) return create Array from sortedArray where { isFirst || orientation( prevCircled, element, nextCircled) >= 0 } }
long orientation(int a, int b, int c) { return (a.x-b.x)*(c.y-b.y)-(a.y-b.y)*(c.x-b.x); }
Некоторые пояснения: Переменные element, isFirst, prevCircled, nextCircled определяются языком работы с коллекциями в соответствующих контекстах.
еlement означает текущий элемент, prevCircled - предыдущий (и последний, если текущий - первый) и т.д.
isFirst - означает, что текущий элемент - первый.
Я считаю что если программа будет записана в таком стиле, то она будет в разы читабельнее соответствующей программы написанной, например, на Java, а уж тем более написанной на языке J.
зашел я значит в бар пива попить, проверил почту и был огорошен Вашим комментарием.
О вкусах, конечно, не спорят... и тем более меня не удивляет, что человека, постоянно пишущего на Java или C++, программа на J пугает... ;-)) Так что пропущу, пожалуй, возможность поучавстваовать в дискурсе о красоте...
Едем дальше... Вы сравниваете программу на языке J, с каким-то неизвестным природе псевдо-кодом... Я не спорю, что можно придумать язык в котором эквивалентная программа будет короче. Можно вообще придумать язык в котором вычисление выпуклой оболочки является примитивной операцией, и тогда программа по ее вычислению выйдет еще короче... ;-))
Однако, сравнение существующего языка с такими эфемерными, несуществующими -- совершенно не в кассу. Так-же как и сравнение универсального языка с каким-то специализированным (для вычисления оболочек), эзотерическим.
J -- универсальный язык и программу вычисления выпуклой оболочки я выбрал для иллюстрации... На J написана масса алгоритмов (просто поищите в интернете, почитайте книжки и статьи на jsoftware.com), для каждого из которых, боюсь, в рамках вашей парадигмы пришлось-бы придумывать собственный язык.
Кроме того, краткие обозначения токенов там совсем не главное, как я неоднократно в тексте и в дискуссии пытался подчекнуть и аргументировать. Можно обозначить ':/' как 'grade_up', а ':/~' как 'sort_up' и программа от этого не станет намного длиннее.
И кроме того, Вы никак не обозначили итерацию, поскольку для удаления вогнутых углов может понадобиться несколько проходов. Или в этом "языке" итерация подразумевается ?
К.Л.М.
beer disclaimer: пишу с КПК из бара после второго пива... опечатки прошу простить.
При условии конечно что весь постинг не был шуткой. Впрочем, он оказался хорошим поводом продемонстрировать силу language-oriented подхода.
Итак, в моем понимании Ваш пример написанный на языке J выглядит абсолютно ужасно.
Для меня критерий красоты программы это тогда когда она написана абсолютно ясно и максимально близко
к тому как задача и ее решение формулировались бы у меня в голове или как бы я ее рассказал на естественном языке другому человеку.
У Вас же восторг вызывает стремление написать программу как можно короче.
Давайте рассмотрим Ваш пример подробнее. Стоит задача - найти выпуклую оболочку для заданного множества точек на плоскости. По Вашим же словам:
Алгоритм этот заключается в том, чтобы
1. Отсортировать точки по углам, относительно самой левой из них (которая по определению принадлежит оболочке).
2. А потом, пройдя по образовавшемуся звездообразному контуру последовательно, начиная с левой точки,
2.1 удалить все, угол при которых (относительно внутренности многоугольника) выгнут наружу (>180ˆ).
Result: Те точки, что останутся, будут образовывать вогнутые углы, а значит оболочка получится выпуклой.
Я скопировал здесь Вашу программу, которая реализует этот алгоритм на J:
s =: ({. , }. /: 12"_ o. }. - {.) @ /:~
l =: 11"_ o. [: (* +)/ }. - {.
rr =: (1"_ , (0"_ > 3: l\ ]) , 1"_) # ]
hull =: [: rr^:_ s
А теперь я попробую написать как выглядела бы с моей точки зрения идеальная программа, реализующая этот же алгоритм.
Для написания этой программы я буду использовать язык подобный Java, расширенный языком работы с коллекциями
(подобный язык в частности будет поставляться вместе с MPS) и зачатками языка манипулирующего точками на плоскости
(или, возможно, вместо него - языка комплексных чисел)
Array
ConvexHull(Collection
points) {
leftPoint = find in points by minimum of p.x
sortedArray = leftPoint + create Array
from points
where element != leftPoint
sorted by angleToXAxis(element-leftPoint)
return create Array
from sortedArray
where { isFirst || orientation( prevCircled, element, nextCircled) >= 0 }
}
long orientation(int a, int b, int c) {
return (a.x-b.x)*(c.y-b.y)-(a.y-b.y)*(c.x-b.x);
}
Некоторые пояснения:
Переменные element, isFirst, prevCircled, nextCircled определяются языком работы с коллекциями в соответствующих контекстах.
еlement означает текущий элемент, prevCircled - предыдущий (и последний, если текущий - первый) и т.д.
isFirst - означает, что текущий элемент - первый.
Я считаю что если программа будет записана в таком стиле, то она будет в разы читабельнее соответствующей программы написанной, например, на Java,
а уж тем более написанной на языке J.
Reply
О вкусах, конечно, не спорят... и тем более меня не удивляет, что человека, постоянно пишущего на Java или C++, программа на J пугает... ;-)) Так что пропущу, пожалуй, возможность поучавстваовать в дискурсе о красоте...
Едем дальше... Вы сравниваете программу на языке J, с каким-то неизвестным природе псевдо-кодом... Я не спорю, что можно придумать язык в котором эквивалентная программа будет короче. Можно вообще придумать язык в котором вычисление выпуклой оболочки является примитивной операцией, и тогда программа по ее вычислению выйдет еще короче... ;-))
Однако, сравнение существующего языка с такими эфемерными, несуществующими -- совершенно не в кассу. Так-же как и сравнение универсального языка с каким-то специализированным (для вычисления оболочек), эзотерическим.
J -- универсальный язык и программу вычисления выпуклой оболочки я выбрал для иллюстрации... На J написана масса алгоритмов (просто поищите в интернете, почитайте книжки и статьи на jsoftware.com), для каждого из которых, боюсь, в рамках вашей парадигмы пришлось-бы придумывать собственный язык.
Кроме того, краткие обозначения токенов там совсем не главное, как я неоднократно в тексте и в дискуссии пытался подчекнуть и аргументировать. Можно обозначить ':/' как 'grade_up', а ':/~' как 'sort_up' и программа от этого не станет намного длиннее.
И кроме того, Вы никак не обозначили итерацию, поскольку для удаления вогнутых углов может понадобиться несколько проходов. Или в этом "языке" итерация подразумевается ?
К.Л.М.
beer disclaimer: пишу с КПК из бара после второго пива... опечатки прошу простить.
Reply
Leave a comment