http://habrahabr.ru/post/221011/
Жесть! Это как программирование через регулярные выражения…
Нет, вы меня не заставите! Больше никогда!
Смотрю на код и чувствую себя идиотом. Это правда не эзотерический язык типа brainfuck? Им кто-то реально пользуется? И эти программы потом читают?
quicksort=: (($:@(<#[), (=#[), $:@(>#[)) ({~ ?@#)) ^: (1<#)
Perl нервно курит в сторонке.
Хабрахабр о JJ —
корейский среди языков программирования. Взрыв на фабрике спецсимволов. Куча скобочек, точек, слэшей, и всё это ещё и работает. Не иначе как по велению чёрной магии, а то и самого Сатаны.
Некоторые из тех, кто пишет на J, забывают простые правила написания
любого кода в погоне за краткостью или просто увлекшись. Эти правила не новые, но они приобретают критическое значение применительно к APL-подобным языкам, потому как при чтении конструкций вроде
((]i.~[:{.[){([:{:[),]`([:<[$:[:>])@.([:32&=[:3!:0[:>]))"2 0
даже тренированный мозг сворачивается в трубочку.
Итак, простые правила написания
читаемого кода на J под катом.
Без
словарика под кат лучше не соваться. Вас предупреждали.
И напомню, список полезных ссылок
здесь.
Пользуйтесь мнемониками
Если неудобно или просто не хочется часто лезть в словарь, чтобы подсмотреть, какими же всё-таки символами обозначается та или иная функция или что значит вон та конструкция — оберните её в глагол:
head =: {.
tail =: {:
head 9 8 3 0 6 1 2 5 4 7
9
tail 9 8 3 0 6 1 2 5 4 7
7
Разделяй и властвуй
Иногда лучше разбить сложную, запутанную конструкцию на несколько более простых.
logistic =: dyad : '(^ - y % x) % x * *: >: ^ - y % x'
exp =: dyad : '^ - y % x'
logistic =: dyad : '(x exp y) % x * *: >: x exp y
Комментарии
Комментарии в J начинаются с
NB.
, и это как раз тот случай, когда их не может быть
много! Если залезть в стандартные библиотеки или промышленный код, можно наткнуться на тонны комментариев; зачастую их в несколько раз больше, чем самого кода: писать самодокументирующийся код на J сложно, и усилия обычно себя не оправдывают.
Больше пробелов, хороших и разных
Средний однострочник на J и так состоит из двадцати слабо на первый взгляд связанных символов, незачем лишний раз усложнять прочтение. Правильно расставленные пробелы и скобки помогут разобраться в структуре даже самого запутанного глагола.
(]%[**:@>:@])[:^[:-%~
(] % [ * *:@>:@]) [: ^ [: - %~
Явное лучше скрытого
Для сложных выражений часто лучше использовать эксплицитную запись вместо тацитной.
(] % [ * *:@>:@]) [: ^ [: - %~
dyad : '(] % (x * *:@>:@])) ^ -y%x'
Хуки и форки — ваши друзья
Для тех, кто не знал или забыл:
(f g) y ⇔ y f (g y)
x (f g) y ⇔ x f (g y)
(f g h) y ⇔ (f y) g (h y)
x (f g h) y ⇔ (x f y) g (x h y)
Эти простые конструкции часто помогают сократить количество кода вдвое-втрое, практически не ухудшая его читаемость.
Управляющие структуры
В J есть все привычные управляющие структуры, но использовать их можно только внутри эксплицитного глагола.
Ветвления работают так же, как в любом другом языке: если условие
T
вернуло 1, переходим к блоку
B
, иначе переходим к следующему блоку
else./elseif.
, если он есть.
if. T do. B end.
if. T do. B else. B1 end.
if. T do. B elseif. T1 do. B1 elseif. T2 do. B2 end.
while.
и
whilst.
исполняют блок
B
, пока
T
возвращает 1, с тем отличием, что
whilst.
пропускает проверку для первого прохода, так что
B
всегда выполняется как минимум один раз.
while. T do. B end.
whilst. T do. B end.
for.
просто выполняет
B
столько раз, сколько элементов в
T
;
for_i.
создаёт переменные
i
и
i_index
— элемент и его индекс соответственно.
for. T do. B end.
for_i. T do. B end.
select.
переходит к первому
Ti
, совпавшему с
T
, выполняя соответствующий блок.
fcase.
—
case.
с «проваливанием».
select. T
case. T0 do. B0
case. T1 do. B1
fcase.T2 do. B2
case. T3 do. B3
end.
Если блок
B
выполнился с ошибкой — выполняем блок
B1
, иначе просто игнорируем его.
try. B catch. B1 end.
Попробуем применить эти правила к решателю судоку из
этого поста.
Исходный исходный код:
i =: ,((,|:)i.9 9),,./,./i.4$3
c =: (#=[:#~.)@-.&0
t =: [:(([:*/_9:c\])"1#])i&{+"1 1(>:i.9)*/[:i&=i.&0
r =: [:,`$:@.(0:e.,)[:;(<@t)"1
s =: 9 9&$@r@,
Итог преобразований:
cells =: ,./^:2 i. 4 # 3
rows_cols =: ((, |:) i. 9 9)
indices =: , rows_cols, cells
no_errors =: verb : '(-: ~.) y -. 0'
substitutions =: verb : '(indices { y) +"1 1 ((>:i.9) */ indices = y i. 0)'
remove_wrong =: verb : 'y #~ */"(1) _9 no_errors\"1 y'
try =: remove_wrong @ substitutions
solve =: verb define
variants =: y
whilst.
0 e. ,variants
do.
variants =: ; (<@try)"1 variants
end.
,variants
)
sudoku =: verb : '9 9 $ solve , y'
Результат работы m
2 0 0 3 7 0 0 0 9
0 0 9 2 0 0 0 0 7
0 0 1 0 0 4 0 0 2
0 5 0 0 0 0 8 0 0
0 0 8 0 0 0 9 0 0
0 0 6 0 0 0 0 4 0
9 0 0 1 0 0 5 0 0
8 0 0 0 0 7 6 0 0
4 0 0 0 8 9 0 0 1
s m
2 8 4 3 7 5 1 6 9
6 3 9 2 1 8 4 5 7
5 7 1 9 6 4 3 8 2
1 5 2 4 9 6 8 7 3
3 4 8 7 5 2 9 1 6
7 9 6 8 3 1 2 4 5
9 6 7 1 4 3 5 2 8
8 1 3 5 2 7 6 9 4
4 2 5 6 8 9 7 3 1
sudoku m
2 8 4 3 7 5 1 6 9
6 3 9 2 1 8 4 5 7
5 7 1 9 6 4 3 8 2
1 5 2 4 9 6 8 7 3
3 4 8 7 5 2 9 1 6
7 9 6 8 3 1 2 4 5
9 6 7 1 4 3 5 2 8
8 1 3 5 2 7 6 9 4
4 2 5 6 8 9 7 3 1
Теперь по коду видно, что он делает! Я считаю, это успех.