J может быть читаемым
Жесть! Это как программирование через регулярные выражения…Нет, вы меня не заставите! Больше никогда!
Смотрю на код и чувствую себя идиотом. Это правда не эзотерический язык типа brainfuck? Им кто-то реально пользуется? И эти программы потом читают?
Perl нервно курит в сторонке.quicksort=: (($:@(<#[), (=#[), $:@(>#[)) ({~ ?@#)) ^: (1<#)
Хабрахабр о J
J — корейский среди языков программирования. Взрыв на фабрике спецсимволов. Куча скобочек, точек, слэшей, и всё это ещё и работает. Не иначе как по велению чёрной магии, а то и самого Сатаны.
Некоторые из тех, кто пишет на 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' Теперь по коду видно, что он делает! Я считаю, это успех.
