Oct. 15th, 2010

kaipa: (Default)
Хотел было написать дополнение к предыдущему посту, но в результате набралось текста на отдельный. А все от того, что я начал играться с J. И он мне настолько нравится, что "приходится" делиться открытиями, хотя я обычно про программирование ничего не пишу.

Начал я с самого простого, с выражения, вычисляющего факториал числа. Оно удивительно компактно:
   */1+i.5
120

Несмотря на компактность, выражение состоит из трех функций. "i.5" генерирует вектор от 0 до 4. "1+" прибавляет к каждому элементу вектора единицу, чтобы получить 1..5. А "*/" перемножает элементы вектора. Само выражение -- 6 символов. Для читаемости можно было бы разбавить пробелами, но это необязательно. Наиболее компактное выражение на Скале, которое приходит на ум:
  (1/:(1 to 5))(_*_)

Возможно, на Хаскеле можно написать короче, но я с Хаскелем пока не знаком.

Если же захотеть завернуть выражение J в функцию, то все несколько сложнее и длиннее. Я долго мучался, пока не разобрался, как написать функцию факториала. Все дело в том, что разбор выражения в J право-ассициативный, поэтому a b x вычисляется как a(b(x)). Но если определять функцию f = (a b), то смысл меняется, хотя я до конца не понял, как. Вот короткий пример, прибавление к трем два, а потом умножение на два:
   2&* 2&+ 3
10
   (2&* 2&+) 3
40

Как выражение в скобках получает из трех сорок, я пока не понимаю. Но для того, чтобы получить ожидаемый результат (10), надо явно указывать суперпозицию функций (оператор @):
   (2&*@(2&+)) 3
10

Поэтому в случае с факториалом, функция определяется так:
  f =: */@(1&+@i.)
  f 5
120

Другой вариант -- использовать оператор инкремента ">:". Это не дает выигрыша в случае выражения, но немного короче для функции:
   f =: */@(>:@i.)
   f 5
120

Интересная фича J -- "компиляция" или преобразование функций, которое разворачивает все примитивы в их простейшие выражения. Пример в предыдущем посте с числом "пи" треугольником, "f." -- оператор "компиляции":
  PiTree =: PiTree f.
  PiTree
([: - [: i. -@]) |."0 1 ([: #~ 1: + 2: * i.) ,/. [: ([: ": [: <.@o. 10x"_ ^ ]) [: <: [: *: ]
После "компиляции" программы становятся максимально короткими, но плохо читаемыми. Симплекс-метод для задачи линейной оптимизации программируется несколькими понятными функциями. Но можно и свернуть в одну.
  [-(({~"1<:@{:)-(i.@#@[=<:@{.@]))*/(({~<:@{.)%({~<@<:))
Объяснение и хорошее введение в язык -- здесь

Profile

kaipa: (Default)
kaipa

April 2017

S M T W T F S
       1
2345678
9101112131415
16171819202122
23242526272829
30      

Page Summary

Style Credit

Expand Cut Tags

No cut tags
Page generated Jul. 16th, 2025 03:58 pm
Powered by Dreamwidth Studios