LINUX.ORG.RU

Сообщения kovrik

 

Имплементация Scheme r5rs макросов

Добрый день!

Подскажите, пожалуйста, есть ли какие-нибудь стандартные алгоритмы для имплементации макросов Scheme R5RS?
Гуглятся какие-то простые примеры на самой же Scheme, либо какой-нибудь спагетти код в котором черт ногу сломит.

Если какие-нибудь канонические реализации (на Java/C++?) или статьи?

Ну, и в общих чертах, с чего начинать?
Реализовал уже весь R5RS, а вот с макросами даже не знаю с чего начать.

Спасибо.
PS: в данный момент изучаю как оно реализовано в Kawa, уж не знаю, поможет ли

 , ,

kovrik ()

Вопрос по Continuations

Всем привет!
Продолжаю пилить свою r5rs, дошло дело до continuations.
Пишу на java, поэтому выбирать средства для манипуляций со стеком особо не приходится: есть только Exceptions.

Соответственно, делаю примерно так, как сделано в Kawa:
https://www.gnu.org/software/kawa/internals/complications.html

Кое-как оно работает, но далеко не всегда, и я уже мозг себе сломал пытаясь понять почему.

Например, этот кусок кода работает правильно (взят с Вики):

(define (f return)
  (return 2)
  3)

(display (f (lambda (x) x))) ; displays 3

(display (call-with-current-continuation f)) ; displays 2

Далее, это тоже работает:
(define (cc) (call-with-current-continuation (lambda (cc) (cc cc))))

(cc) ;; => #<continuation>

А вот это уже не работает:
(define (cc) (call-with-current-continuation (lambda (cc) (cc cc))))
((cc) display) ;; должно выводить #<procedure:display>

((cc) display) кидает CalledContinuation exception.
И вот тут я не понимаю, что я должен с этим делать.
Kawa пишет:


If it is “our” continuation, return the value passed to the continuation; otherwise re-throw it up the stack until we get a matching handler.


Что значит «our»?
Даже если я оберну ту строчку, в которой кидается CalledContinuation в try-catch и буду ловить CalledContinuation, то что мне потм с ним делать?

PS: ying-yang puzzle тоже не работает: выводит первые два символа, потом тоже кидает CalledContinuation, с которым тоже не знаю что делать.

 ,

kovrik ()

Numerical tower в Racket и прочих Scheme

Всем привет!
Продолжаю пилить свой Scheme на Java, сейчас реализую numerical tower. Осталось сделать только complex numbers.

1)
Но тут возник вопрос: как надо правильно реализовывать numerical tower?
Проблема в том, что в Java numerical tower нет, да и вообще, числа реализованы довольно кривовато - много special cases, ограничений и костылей.
Мне бы хотелось использовать встроенные в джаву int, long, float, double и др. числовые типы + добавить свои. Только вот как по-хорошему скрестить ежа с ужом?

Одна из проблем: не очень понятно как красиво и просто конвертировать из одного типа в другой (автоматически). Например, чтобы дефолту всегда использовались int, если их не хватает, то автоматически переходить на long, потом BigInteger и тд.

Есть какие-нибудь стандартные подходы к данной проблеме?

Нашел вот такую штуку:
http://www.ccs.neu.edu/racket/pubs/padl12-stff.pdf

2)
Не понимаю один пример в Racket:

> #e2.3
23/10

> (inexact->exact 2.3)
2589569785738035/1125899906842624

В Guile оба возвращают одно и то же, что ИМХО логично.

В Racket просто решили сделать такую 'оптимизацию', чтобы лишних вычислений не делать?

 , ,

kovrik ()

Оптимизации в Scheme

Всем привет!
Продолжаю пилить свою имплементацию Scheme R5RS на Java. В качестве тестов беру примеры кода из Интернета.
Где-то месяц назад взял следующий замечательный пример: https://rosettacode.org/wiki/Integer_roots#Scheme

Тут и internal definitions, и много вычислений, и большие числа, и рекурсия.
Изначально оно падало почти мгновенно со StackOverflowError (что логично). Реализовал tail-call optimizations, падать перестало. Теперь результат немного не совпадает из-за того, что в некоторых местах теряется точность (вообще, числа в Java реализованы кривовато ИМХО), но это ладно. Еще оно работает существенно медленнее Racket и Guile.
Я, конечно, и не ожидал супер производительности, но всё же решил запустить профайлер и по возможности увеличить производительность.

В результате работы профайлера выяснилось, что как минимум 2 вещи существенно снижают производительность:
1) Вызовы процедур
2) Частые environment lookups

1) Вызовы процедур

Одно из очевидных решений - инлайнить некоторые процедуры.
Так, например, делают и Racket, и Guile.

Что-то вроде:

(define (test n) (zero? n)) => (define (test n) (= n 0))

Попытался это реализовать, вроде, получилось, но как-то кривовато.

Вопрос:
Есть ли какие-нибудь алгоритмы для этого дела?
Как определить когда можно инлайнить, а когда нельзя?

Например:

(define (t n)
  (zero? n)   ;; можно инлайнить
  '(zero? n)) ;; нельзя инлайнить

Можно ли как-то статически определить, что перед нами вызов функции, а не quoted form или еще что-нибудь?

В данный момент я просто рекурсивно пробегаю по всем формам в теле функции, и если какой-нибудь элемент совпадает с телом функции, которую можно инлайнить, то я подменяю вызов функции на ее тело (попутно подставляя правильные имена аргументов). Все quoted/quasiquoted формы пропускаю.
Оно, вроде, и работает, но не уверен, что оно будет работать всегда правильно. Плюс, каждый раз приходится создавать кучу новых объектов, потому что списки в Java копируются как shallow copies, а мне здесь всегда нужна deep copy (потому что я не могу менять тело той функции, которую инлайню).

Racket пишут, что они это делают на этапе компиляции - как они это делают?
У меня компиляции нет, ее заменяет вычисление lambda.

2) Частые environment lookups

На пальцах я понимаю, почему оно работает не так шустро и чисто теоретически представляю, как это исправить. На практике же ничего не получается.

Допустим, есть простая функция:

(define (perf n)
  (if (zero? n)
    "DONE"
    (perf (- n 1))))

У меня, когда вычисляется ее тело, то evaluator на каждой итерации постоянно забирает из окружения символы if, zero?, n и perf. Более того, для всех символов, кроме perf, он всегда делает по 2 lookup'а: сначала пытается найти в локальном окружении, не находит, потом поднимается выше и находит их в глобальном окружении.
Итого, даже если вычислить (perf 1), то lookups будут примерно такие (воспроизвожу по памяти):

Lookups:

perf
if (miss!)
if
zero? (miss!)
zero?
n
perf
- (miss!)
n
if (miss!)
if
zero? (miss!)
zero?
n

(здесь я еще опускаю lookups, которые делаются для тела zero?: = и n)

Видно, что многие lookups являются лишними и можно бы их прокешировать. Но как?
Во-первых, что и как кешировать? Во-вторых, как при этом не поломать lexical scope?

 ,

kovrik ()

Parser combinators и LL(2)

Здравствуйте!

Можно ли совместить LL(1)/LL(2) парсеры и parser combinators?
Или это невозможно?

Насколько я понимаю, допустим, LL(2) парсер имеет lookahead = 2, т.е. он может смотреть на 2 токена вперед (кстати, что есть токен в данном случае - один символ или именно целый токен?).
Это сильно ограничивает backtracking (нельзя, например, прочитать 10 токенов, подумать, а потом откатиться назад).
А без backtracking'а по сути не будут работать многие parser combinators, да? Например, комбинатор `and`: допустим, он распарсил успешно 5 токенов, а на 6м зафейлил, следовательно, вся цепочка должна зафейлиться, но откатить 5 токенов мы уже не можем.
Или parser combinators являются LL(infinity) парсерами?
Можно ли сделать parser combinators поверх потоков (streams)?

 ,

kovrik ()

Вопрос по quasiquote и unquote-splicing

Продолжаю пилить свою имплементацию r5rs на Java.

Наконец дошли руки до quasiquote/unquote/unquote-splicing.

Скажу честно - это кошмар какой-то. Читаешь и, вроде, все более-менее понятно. Довльно простые штуки.

Но потом оказывается, что там стопицот особых случаев. И код превращается в непонятную кашу сплошных if-else'в (не говоря уже о том, что в разных Схемах quasiquote работат немного по-разному).

А, да, всю эту quasi-кашу делаю через list и append (http://repository.readscheme.org/ftp/papers/pepm99/bawden.pdf)

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

`(1 ,@())

Как эта штука должна работать?

Guile ругается:

guile> `(1 ,@())

Backtrace:
In standard input:
   5: 0* (quasiquote (1 (unquote-splicing ())))

standard input:5:1: In procedure memoization in expression (quasiquote (1 #)):
standard input:5:1: Illegal empty combination ().
ABORT: (syntax-error)

Racket не ругается и выдает:

Welcome to Racket v6.2.1.
> `(1 ,@())
'(1)

Chicken Scheme:

#;1> `(1 ,@())

Error: illegal non-atomic object: ()
inside expression `(##sys#cons ...)'

        Call history:

        <syntax>          (quasiquote (1 (unquote-splicing ())))
        <syntax>          (##sys#cons (##core#quote 1) ())
        <syntax>          (##core#quote 1)      <--

Если перевести это на аналогичный код в Clojure, то он выдает ответ, аналогичный Racket'у:

user=> `(1 ~@())
(1)

Кто прав?

Чисто интуитивно я согласен c Guile и Chicken:

unquote-splicing пыдается вычислить последующую форму (и если она вернет список, то оно подставит элементы списка вместо себя).

Форма после unquote-splicing - пустой список без quote: ()

Оно пытается его выполнить и фейлится (что логично и понятно).

Если «починить» этот пример, добавив quote, то все работает:

guile> `(1 ,@'())
(1)

Но я не совсем понимаю как Racket и Clojure выполняют эту штуку и возвращают '(1).

Ладно, Clojure еще можно понять, там () evaluate'иться в () (quote не нужен). Но Racket?

Или это очередной особый случай?

 , , ,

kovrik ()

Пара вопросов по реализации Scheme

Продолжаю свою эпопею по имплементации r5rs на Java.
D общем-то, все (что реализовано) работает, совпадает с результатами в Guile, Racket и Chicken Scheme.
Беру рандомные примеры с Rosetta Code - в 90% случаев они выполняются правильно, в остальных - нахожу какую-нибудь багу и чиню ее.
Но, периодически возникают различные вопросы по реализации. В Интернете найти вразумительныe ответы не всегда получается.

Вопрос 1:
Как в современных Лиспах/Схемах реализованы списки?
Действительно ли везде берут Cons и из них создают связный список?

Изначально в своей реализации в качестве списков я просто использовал джавовский LinkedList (точнее, наследовал свой класс от него).
Все прекрасно работает, плюс, бесплатно получаю все оптимизации, все полезные методы LinkedList'а, реализацию интерфейсов List, Deque.
Cons же сделал просто отдельным классом, который используется в некоторых случаях, а при любой возможности перехожу на List.

Потом я решил все-таки сделать нормальный Cons и Cons Lists (та еще задача!) - и началось...
Казалось бы, такая простая штука - тупо пара двух значений.
Но потом оказывается, что там много нестандартных специальных случаев, когда эта штука ведет себя немного по-другому (nil-terminated lists, dotted notation, cyclic lists etc. NIL объект должен быть синглтоном. Плюс, так как это Джава, то нельзя использовать рекурсию, все приходится переделывать в итеративную версию)

В итоге, я, конечно, реализовал Cons-ячейку и списки из них, но, как мне кажется, больше потерял, чем приобрел.
Во-первых, непонятно как связать уже готовый класс, который наследует от LinkedList и новый Cons.
Во-вторых, теряются все полезные свойства стандартных джавовских коллекций.

Так вот, действительно ли сейчас реализовывают списки через кучу связанных Cons cells?

Есть ли какой-нибудь красивый и простой способ остаться на стандартных джавовских коллекциях, реализовать и список, и cons-ячейку, да еще и сделать, чтобы список был реализован непосредственно через cons'ы, либо наследовал от них?


Вопрос 2:
Есть ли какой-то стандартных набор юнит тестов/кейсов на которых можно было бы тестировать свою имплементацию?
Т.е. если все эти тесты пройдены, то имплементация считается успешной.
Я, конечно, стараюсь покрывать все возможные случаи, плюс, проверяю на примерах из Интернетов (той же Rosetta Code), но в спецификации же полно редких случаев и тп.

 ,

kovrik ()

Вопрос по short-hand специальных форм в Scheme

Являются ли short-hand специальных форм макросами в Схеме?

Например, quote - есть special form.
Что есть ее short-hand вариант '?

Пример:

'(+ 1 2) => (quote (+ 1 2)) => (+ 1 2)

Превращение из 'form в (quote form) происходит на фазе read или macroexpand?
Т.е. когда ридер видит ', то должен ли он вернуть токен ' без изменений (который потом во время macroexpansion превратится в quote) или же ридер сразу должен вернуть список (quote form) без каких либо макросов?

Или без разницы и зависит от имплементации?

 , ,

kovrik ()

Promises в Scheme и других ЯП

Добрый день!

Пишу сейчас на коленке имплементацию Scheme (r5rs) на Java (да, полностью r5rs на джаве не получится реализовать, но это и не планируется).
Немного запутался в delayed evaluation'ах и в promises.

Если открыть, например:
http://community.schemewiki.org/?delayed-computation

то там пишут:


A promise is, quite simply, the promise to evaluate an expression later.
It is not evaluated until explicitly requested, although R5RS permits promises to be evaluated implicitly when passed to primitive operations and their result be used instead.


Тоже самое пишут и на:
https://docs.racket-lang.org/reference/Delayed_Evaluation.html


A promise encapsulates an expression to be evaluated on demand via force.
After a promise has been forced, every later force of the promise produces the same result.



Т.е. promise - это просто выражение, которое мы вычислим когда-нибудь потом, либо явно через force, либо неявно.
Результат запоминается после вычисления и повтороное вычисление promise'а всегда возвращает сохраненный результат.

API для promise'в довольно простой: delay, да force.
И разные вспомогательные promise?, promise-forced?, promise-running?

Если же посмотреть promises в JavaScript или Java:
https://www.promisejs.org/implementing
https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletableFut...

То, как я понимаю, речь немного о другом.
Future - read-only 'контейнер' для результата будущих вычислений
Promise - writable 'контейнер' для результата будущих вычислений

Т.е. допустим, мы создаем Promise и передаем его куда-нибудь, обещая положить туда результат неких вычислений когда-то в будущем.
На той стороне (обычно, в другом треде) получают созданный нами promise и в нужный момент пытаются получить его результат (блокирующий вызов).
API намного сложнее.

Как я это вижу:
в Java/JS/... - это concurrency примитив, 'контейнер' для результатов (часть методов которого - блокирующие)
в Scheme promise - это control feature, которая просто позволяет делать delayed evaluation

Так ли это?

Второй вопрос:
Будет ли в Scheme какая-то принципиальная разница (кроме memoization) между promise и обычным s-expr?

(force (delay (+ 1 2))) ; => 3
(eval  (quote (+ 1 2))) ; => 3

Т.е. должен ли я использовать Java'вский CompletableFuture (aka Promise) для реализации Scheme Promise
или достаточно будет создать обычный класс Promise, который просто хранит тело выражения (s-exp) и результат (если есть), а force просто берет тело и выполняет его (передает хранящийся в promise s-exp evaluator'у)?

 , ,

kovrik ()

Java вопрос по synthetic's и Class.getDeclaredConstructors()

Здравствуйте!

В Java у класса Class есть метод getDeclaredConstructors(). В JavaDoc'е к этому методу есть комментарий:

This method returns an array of length 0 if this Class object represents an interface, a primitive type, an array class, or void.

Звучит вполне логично. Проверяем:

System.out.println("Interface: " + Runnable.class.getDeclaredConstructors().length);
System.out.println("Primitive: " + int.class.getDeclaredConstructors().length);
System.out.println("Array:     " + int[].class.getDeclaredConstructors().length);
System.out.println("void:      " + void.class.getDeclaredConstructors().length);

Выдает:

Interface: 0
Array:     0
Primitive: 0
void:      0

Все ок.

На Хабре недавно был список задач по Джаве и один из вопросов как раз был «Может ли класс в Java не иметь конструкторов?».

В качестве решения было предложено:

public class Main {

  static class Nested {
    private Nested() {}
  }

  public static void main(String[] args) throws ClassNotFoundException {

    new Nested();
    System.out.println("  Main$1:    " + Class.forName("Main$1").getDeclaredConstructors().length);
  }
}

Выдает 0.

Почему так?

$1 как бы намекает, что это анонимный класс.
Но, во-первых, про анонимные классы в JavaDoc'е ни слова.
Во-вторых, проверим:

System.out.println("  Serializable: " + new Serializable(){}.getClass().getDeclaredConstructors().length + 
                   ", isAnonymousClass(): " + new Serializable(){}.getClass().isAnonymousClass());

// печатает 'Serializable: 1, isAnonymousClass(): true'

Т.е. наш анонимный класс имеет 1 конструктор.

Проверим для решения из Хабра, является ли тот класс анонимным:

System.out.println("  Main$1:    " + Class.forName("Main$1").getDeclaredConstructors().length + 
              ", isAnonymousClass(): " + Class.forName("Main$1").isAnonymousClass());

// печатает 'Main$1:    0, isAnonymousClass(): true'
Т.е. класс анонимный, но конструктора нет.

Копаем дальше:

    System.out.println("  Main$1:    "          + Class.forName("Main$1").getDeclaredConstructors().length +
                       ", isAnonymousClass(): " + Class.forName("Main$1").isAnonymousClass() +
                       ", isInterface(): "      + Class.forName("Main$1").isInterface() +
                       ", isPrimitive(): "      + Class.forName("Main$1").isPrimitive() +
                       ", isArray(): "          + Class.forName("Main$1").isArray() +
                       ", isEnum(): "           + Class.forName("Main$1").isEnum() +
                       ", isLocalClass(): "     + Class.forName("Main$1").isLocalClass() +
                       ", isAnnotation(): "     + Class.forName("Main$1").isAnnotation() +
                       ", isSynthetic(): "      + Class.forName("Main$1").isSynthetic() +
                       ", isMemberClass(): "    + Class.forName("Main$1").isMemberClass());

Выдает:

Main$1:    0, 
isAnonymousClass(): true, 
isInterface():      false, 
isPrimitive():      false,
isArray():          false,
isEnum():           false,
isLocalClass():     false,
isAnnotation():     false,
isSynthetic():      true,
isMemberClass():    false

Ага, видим, что класс синтетический:

indicates that this class or interface was generated by a compiler and does not appear in source code.

Т.е. синтетические - это классы/методы/конструкторы, которые компилятор создает сам, которых нет в исходниках.
Как известно, компилятор знает только о top-level классах. Он ничего не знает про nested, inner и тп.
Для их взаимодействия, например, он и создает синтетические классы, методы и конструкторы.

Все встает на свои места.

Но, если мы выполним:

public class Main {

  static class Nested {
    private Nested() {}
  }

  public static void main(String[] args) throws ClassNotFoundException {

    new Nested();
    System.out.println("  Main$1:       "       + Class.forName("Main$1").getDeclaredConstructors().length +
                       ", isAnonymousClass(): " + Class.forName("Main$1").isAnonymousClass() +
                       ", isSynthetic(): "      + Class.forName("Main$1").isSynthetic());

    System.out.println("  Main$Nested:  "  + Class.forName("Main$Nested").getDeclaredConstructors().length +
                       ", isAnonymousClass(): " + Class.forName("Main$Nested").isAnonymousClass() +
                       ", isSynthetic(): "      + Class.forName("Main$Nested").isSynthetic());

    System.out.println("  Serializable: " + new Serializable(){}.getClass().getDeclaredConstructors().length +
                       ", isAnonymousClass(): " + new Serializable(){}.getClass().isAnonymousClass() +
                       ", isSynthetic(): " + new Serializable(){}.getClass().isSynthetic());
  }
}

То получим:

  Main$1:       1, isAnonymousClass(): true,  isSynthetic(): false
  Main$Nested:  2, isAnonymousClass(): false, isSynthetic(): false
  Serializable: 1, isAnonymousClass(): true,  isSynthetic(): false

Если добавляю Main$2, Main$3, то они равны Main$1 (вангую, что это три анонимных Serializable).
Main$4 класса нет. Кидает эксепшн.

Вопрос 1: Куда делся синтетический класс без конструкторов? Nested класс же остался.
Вопрос 2: Почему Main$Nested имеет 2 конструктора? Один - default. А второй?
Вопрос 3: Можете еще привести примеры synthetic's? Нагуглил что-то про switch-statement, но воспроизвести не удалось.

Извините за простыню. Спасибо.

 

kovrik ()

Clojure persistent / transient

Видимо, не до конца понимаю суть persistent / transient.

Код 1:

(defn duplicate [s]
  (let [result []] ; будем заполнять persistent вектор result
    (doseq [e s]   ; для каждого элемента вектора s (аргумент)
      (println e)  ; выводим его на экран
      (conj result e e)) ; добавляем два таких элемента в result
    result)) ; возвращаем result 

(defn -main [& args]
  (println (duplicate [1 2 3])))
Выводит:

1
2
3
[]

Код 2:

(defn duplicate! [s]
  (let [result (transient [])] ; будем заполнять transient вектор result
    (doseq [e s]   ; для каждого элемента вектора s (аргумент)
      (println e)  ; выводим его на экран
      (conj! result e) ; добавляем два таких элемента в result
      (conj! result e))
    (persistent! result))) ; возвращаем persistent result 

(defn -main [& args]
  (println (duplicate! [1 2 3])))
Выводит:

1
2
3
[1 1 2 2 3 3]

Почему первый код не работает?
Плохо ли в данном случае использование transient?
Можно ли сделать без transient?

Ведь persistent != immutable, так?
В первом коде он, по идее, на каждый вызов conj должен создавать новый вектор (у которого 1 новый элемент, а остальные шарятся между предыдущими версиями вектора).
Почему в итоге возвращает пустой вектор?

 

kovrik ()

Lock-free Circular Fifo Buffer - возможно ли такое?

Вот есть CircularFifoBuffer.
Его можно обернуть в BufferUtils.synchronizedBuffer(), тогда он будет синхронизованным, но, как я понимаю, не будет lock-free?

Возможно ли его сделать lock-free (CAS, как в AtomicInteger.incrementAndGet(), только здесь будет что-то вроде addAndRemove())?
Правильно ли я понимаю, что невозможно сделать атомарной операцию удаления одного элемента + добавление другого?

 , , ,

kovrik ()

Java-класс для представления выборок из базы

Здравствуйте.
Суть задачи: есть таблица с данными и есть web-интерфейс. В интерфейсе настраиваются параметры запроса (выбор даты, выбор столбцов таблицы, фильтры, группировка, сортировка) и делается запрос.
На основе выбранных параметров формируется sql-запрос.

Вопрос:
Какой класс лучше всего сделать, чтобы можно было удобно записывать и считывать оттуда произвольные выборки?

Т.е. допустим, выбрал юзер поля User, Country, Time и метрики Installs, Clicks.
Для представления всего этого придумывается что-то вроде map'ы, в которой значением будет Map<Metrics, Double> (где metrics - метрика, а double - это значение метрики).
А вот ключем, по идее, может быть любой произвольный набор полей - Key<User, Country> или Key<Country> или Key<Country, User> и тд.

Т.е. для ключа важно:
1. Произвольное количество и порядок элементов.
2. Уникальность элементов (чтобы не было Key<User, User>).
3. Сохранение информации о классе элемента (чтобы потом знать, что elem.getId() - это id юзера, а не страны).
4. Чтобы Key был comparable.
5. Ну и чтобы он не был слишком уж тяжелым и медленным.

На ум приходит только:
Создать интерфейс/абстрактный класс Field, у которого будет некая метка CLASS_ID. Все сущности-поля будут реализовывать/наследовать от Field'а и у каждого будет константное значение этой метки (например, User - 1, Country - 2 и тд).
И тогда ключем будет просто какой-нибудь TreeSet<Field>.
Но такой подход кажется очень громоздким.
Или нет? Какие еще есть варианты?

 , , ,

kovrik ()

Conversion funnels

Помогите разобраться с conversion funnels' analysis. К сожалению, не знаю термина на русском (буквально? конверсионные воронки?).

Суть в чем: этот анализ позволяет выявить пути (tracks) по которым пользователи пришли к чему-либо и процент конверсии - например, у нас есть приложение, в приложении - кнопка Купить товар. Нас интересует, какие события (путь) обычно предшествует покупке товара (т.е. что делало большинство юзеров перед тем как купить товар). Например, юзер Нажал на ссылку Special Offers (событие A), а потом сделал покупку (событие B).

Результат этого анализа, обычно, представляет из себя столбчатую диаграмму: каждый столбец - это событие. Последний столбец - интересующее нас действие (покупка товара),

Допустим, за некий период времени было 100 покупок. Из них 60 - по funnel'у A-B.
При этом, событие А инициировало 80 юзеров -> процент конверсии равен 75%.
Остальные 40 покупок - через обычное меню. При этом, нажали на Меню 200 человек - процент конверсии равен 20% - намного меньше, чем через Special Offers. Видно, что нужно стремиться направлять юзеров по funnel'у A-B.

Пример можно найти например на (http://blog.mixpanel.com/2009/06/10/introduction-to-analytics-funnel-analysis/). Не реклама, просто первая ссылка в гугле.

Не знаю, насколько точно это описание. Никаких годных статей найти не удалось.

Так вот, какие вопросы:

1. Как считается конверсия? Правилен ли пример выше?

2. Как высчитывается срок действия funnel'а? Т.е. как высчитывается максимальный промежуток времени между двумя событиями, чтобы мы посчитали их в один funnel? Тот же mixpanel держит каждый funnel 30 дней. ИМХО это очень много (хотя ясно, что зависит от области применения). Flurry в играх сбрасывает начинает новый funnel если игрок свернул игру более чем на 10 секунд.

3. Непонятно как высчитываются пути. Допустим, юзер добавил 10 событий. Нужно считать все возможные комбинации этих событий (факториал 10)?

4. Как все это лучше всего реализовать с технической точки зрения? Etsy для funnel analysis'а использует Hadoop. Всегда ли это нужно? Какие структуры данных использовать для хранения этой статистики? В каком виде эти данные представлять? Как рассчитывать funnel'ы и процент конверсии?

 , ,

kovrik ()

Проблема с отрисовкой vim'а

С недавних пор (после ковыряния в конфиге и удаления powerline) появилась бага: при заходе в вим начинает ехать отрисовка. Например, нажимаю hjkl - и статус-бар как бы плывет вверх на каждое нажатие и появляется куча артефактов.
Бага возникает только в sakura (в urxvt все норм).
При этом, если засуспендить вим (C-z), а потом вернуться - fg, то все начинает работать.
Когда был установлен powerline - тоже все работало норм.
В чем проблема?

 

kovrik ()

Выбор ультрабука

Здравствуйте.
Решил обновить свой старенький Acer. Ноут планирую использовать в основном для работы (программирование), плюс серфинг в Интернете и просмотр фильмов.

Требования:
- большое время работы
- чтобы был достаточно мобильным
- хороший дисплей
- SSD

Сейчас, по сути, выбираю между следующими моделями:
1. Lenovo X1 Carbon
2. Lenovo T430(s)
3. MacBook Air
4. MacBook Pro

Внешне мне нравятся и маки, и леново. И те, и другие достаточно минималистичны, хорошая сборка, выглядят красиво. Идеология, конечно, разная, но не суть. Так что, внешний вид не обсуждается.

Lenovo. Пишут, что не шибко большое время работы, НО у T430 можно поставить дополнительный аккумулятор. X1 Carbon легче, тоньше и приятнее, чем T430(s), но в нем смущает отсутствие Ethernet-разъема и малое количество USB (всего 2).
T430 (или T430s - тоже так и не понял какой лучше) уже не выглядит таким мобильным как Carbon - толстый, да и весит прилично. Зато мощнее и с портами/разъемами лучше, чем у Карбона. Да и в инете пишут, что шумный и время жизни не шибко большое. Ну и, само собой, дисплей - не Retina.
Ах, да, еще стоит добавить, что в линейке Lenovo я вообще запутался - все эти серии T, Z, W, Y, X...Кошмар.

Mac. Равнодушен ко всей этой идеологической войне. Мне главное, чтобы самому нравилось и чтобы работало. Так что, холивар разводить не хочу.
У макбуков, конечно, отличный дисплей Retina, хорошее время жизни, хороший тачпад. MacBook Pro - мощный, Air - легкий и тонкий. С портами/разъемами все хорошо. Но, как и в случае с Lenovo, не могу определиться - Pro или Air?
Что смущает в маках:
- переплата за то, что это Apple;
- нестандартная клавиатура и некоторые разъемы
- в Макоси я не работал. Да, там и MacVim можно поставить, и NetBeans, и, в общем-то, весь остальной софт (либо тот же, либо аналогичный). Но для меня это всё будет в новинку. Если же ставить на него Линукс, то, спрашивается, а зачем тогда покупать Мак? Так ли это?

Я прекрасно понимаю, что идеального ноутбука в природе нет. у каждого из вышеперечисленных есть свои плюсы и минусы. Вопрос только в том, какие плюсы и минусы существенны.
По сути, надо определиться сначала, будет ли это Lenovo или Mac.
А затем, будет ли это X1 Carbon или T430, либо же MacBook Pro или Air.

Помогите с выбором.
Спасибо.

 , , , ,

kovrik ()

maven и зависимые друг от друга проекты

Здравствуйте.
Помогите разобраться с maven'ом.
Есть проекты A, B, C. У проекта A в зависимостях стоят проекты B и C.
Билдю в нетбинзе. При этом билдится только сам проект A (даже если делать Build with dependencies).
Как сделать, чтобы при билде проекта A билдились и B, и C и кидались в /lib?
Модули? Assembly? Reactor? Запутался уже. Толком ничего не получилось.

PS: при этом web-проекты билдятся с зависимостями - те, как и надо, кидаются в WEB-INF/lib

 ,

kovrik ()

wait в for loop'е

Здравствуйте.
Допустим, есть конструкция вида:

perl $HOME/test.pl 1 > $HOME/test1.log &
perl $HOME/test.pl 2 > $HOME/test2.log &
perl $HOME/test.pl 3 > $HOME/test3.log & wait
Как засунуть ее в цикл for? Так?
for n in `seq 1 $COUNT`
do
    perl $HOME/test.pl $n > $HOME/test$n.log &
done
& wait;
Т.е. нужно в цикле for запустить COUNT процессов и дождаться выполнения ВСЕХ их.

 

kovrik ()

Отваливается инет при подключении к vpn

Здравствуйте.
Есть нетбук с Убунту. Дома есть роутер D-Link DIR-320. Он раздает инет. На работе есть офисная VPN.
Подключаюсь к VPN'ке - первые 3-10 секунд все ок, а потом инет отваливается. Всегда. Иногда успеваю зайти на сервер, что-то сделать, а иногда инет сразу отваливается.
Куда смотреть? Какие выхлопы нужны?

 

kovrik ()

Multi-dimensional БД с Java биндингом

Возникла задача работы с огромными массивами данных.
Вопросы:
1. Есть OLAP. А какие есть альтернативы?
2. Если использовать OLAP, то что посоветуете?

Нужна бесплатная шутковина, которая развивается, по которой есть документация, биндинги для Java и которая шустрая и эффективная.

Нагуглил:
- SciDB - вроде всё круто, но биндингов для Java не нашел
- Pentaho Mondrian - Java, open-source, но довольно муторная и не чистый OLAP, а надстройка над реляционной БД
- какая-то InterSystems Globals DB (http://globalsdb.org/getting-started/) - Java, бесплатная, но ни разу про нее не слышал. Кто-нибудь использовал ее?

Какие-нибудь другие БД?

PS: с OLAP'ом раньше не работал

 , , ,

kovrik ()

RSS подписка на новые темы