Oct. 13th, 2015

thedeemon: (office)
Занимался тут исследовательским/экспериментальным кодом, а там получилось, что одни и те же действия делаются с двумя похожими наборами данных (горизонтальные и вертикальные координаты), большую часть времени независимо. И захотелось вместо того, чтобы писать одинаковый код и следить, как бы не передать куда иксы вместо игреков, просто лифтануть имеющиеся функции, чтобы они работали сразу с парами значений.
На хаскеле для этого достаточно описать, каким образом диагональный функтор (гомогенные туплы) является аппликативным. Что-то вроде:

data Pair a = P a a 
  deriving (Functor, Show)

instance Applicative Pair where
  pure x = P x x
  P fa fb <*> P xa xb = P (fa xa) (fb xb)


(вот только на самом деле не хочется определять свой тип, было бы здорово обычные туплы (а,а) там использовать)

Но у меня тот проектик был не на хаскеле, а на D. Там подход чуть иной. Сперва как оно выглядит в использовании:

unittest {
    int  f1(string s)                { return s.length; }
    int  f2(int x, int y)            { return x + y; }
    bool f3(int a, string b, bool c) { return c && (a <= b.length); }

    auto r1 = tmap!f1( tuple("aa", "bbb") );
    writeln(r1); // (2,3)

    auto r2 = tmap!f2( tuple(10,20), r1 );
    writeln(r2); // (12, 23)

    auto r3 = tmap!f3( r2, tuple("one", "five"), tuple(true, false));
    writeln(r3); // (false, false)
}


А вот как это реализовано:

alias Dbl(T) = Tuple!(T,T);
alias Double(Ts...) = staticMap!(Dbl, Ts);

auto tproject(int pos, Ts...)(Ts args) {
    enum projStr = iota(args.length).map!(i => format("args[%s][%s]", i, pos)).join(", "); 
    return mixin("tuple(" ~ projStr ~ ")");
}

auto tmap(alias f)(Double!(Parameters!f) args) {
    return tuple(f(args.tproject!0.expand), f(args.tproject!1.expand));
}


По шагам:
tmap получает некоторую функцию f в качестве compile-time-known параметра, и набор рантайм-аргументов args, типы которых вычисляются как Double!(Parameters!f). Parameters - это типовая ф-я из стандартной библиотеки, она возвращает список типов аргументов переданной ей ф-ии. К этому списку мы применяем типовую функцию Double, которая просто маппит список, преобразуя каждое значение функцией Dbl, которая всякий Т превращает в Tuple!(T,T), где Tuple - контейнер из стандартной библиотеки. В результате, например, если исходная функция f принимала аргументы типов (string, bool, int[]), то tmap!f будет принимать аргументы типов (Tuple!(string, string), Tuple!(bool, bool), Tuple!(int[], int[])).
Возвращает tmap, понятное дело, тоже тупл, полученный применением исходной ф-ии к соответствующим элементам входных туплов. Для этого ей надо разделить набор входных туплов на два набора - левые и правые половины оных. Для такой проекции из набора туплов в набор их частей описана ф-я tproject. В принципе, ее наверняка можно реализовать более чистым образом, но я использовал тупую кодогенерацию. Если args это набор туплов, то args[0] это первый тупл, а args[0][0] это первое значение из первого тупла. Т.е. чтобы взять все первые значения нам нужен tuple(args[0][0], args[1][0], args[2][0]...). Такая строчка генерится в компайл-тайме в первой строке tproject и тут же вставляется во вторую строчку, так получается нужное значение.
А, насчет синтаксиса. args.tproject!0 это (благодаря Universal Function Call Syntax) то же самое, что tproject!(0)(args), т.е. передаем компайл-тайм аргумент 0 (это будет pos), и рантайм-аргумент args, а второй компайл-тайм аргумент Ts - это список типов args, он выводится/извлекается автоматически. Три точки говорят, что это не одно значение, а набор значений (несколько аргументов). Чтобы развернуть библиотечную структуру Tuple в набор передаваемых значений, делается .expand.
Вот и все, дешево и сердито. А как такое делается на вашем языке программирования?

teh drama

Oct. 13th, 2015 10:06 pm
thedeemon: (office)
Release manager of Haskell Platform пишет, что уходит, т.к. не осилил морально переход на FTP в 7.10 (это когда вместо
and :: [Bool] -> Bool
теперь
and :: Foldable t => t Bool -> Bool
и с остальными прилюдными ф-ями аналогичная метаморфоза).

Profile

thedeemon: (Default)
Dmitry Popov

July 2025

S M T W T F S
  12345
6789101112
13141516171819
20212223242526
27282930 31  

Most Popular Tags

Style Credit

Expand Cut Tags

No cut tags
Page generated Aug. 29th, 2025 02:14 am
Powered by Dreamwidth Studios