LINUX.ORG.RU
ФорумTalks

а в вашем любимом ЯП есть что-то подобное?

 ,


2

4

Прекрасное введение в линзы, отличная статья, с подробными примерами и интересным оформлением, в отличии от скучных статей про монады. Заодно показывает суть хабра:

http://habrahabr.ru/post/189712/

а в вашем любимом ЯП такое есть?

затравка для Ъ:

«Если ты хочешь использовать композицию функций, где фунция имеет два аргумента», говорит Шерлок, «тебе нужно (.).(.)!”» «Это похоже на испуганную сову», восклицает Ватсон

Мы так близки к линзам! «Ммм я почти общущаю вкус линз Ватсон» расплывается от счастья Шерлок. «Линзы позволяют тебе выполнять композицию функций, fold и обходы (traversals) вместе. Я чувствую как функторы и fold -ы перемешиваются во рту прямо сейчас!»

★★★★★

Последнее исправление: cetjs2 (всего исправлений: 1)

Ответ на: комментарий от qnikst

Впрочем близких аналогов lenses в яве нет

А в чём проблема-то?

public interface F<A,R> {
   public R apply(A a);
}

public interface Setter<A,R> {
   public Collection<R> apply(F<A, R> f, Collection<A> a);
}

Collection<T2> over (Setter<T1,T2> s, F<T1,T2> func, Collection<T1> data)
{
    return s(func, data);
}
monk ★★★★★
()
Ответ на: ОГО от Sigrlami

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

Sigrlami
()
Ответ на: комментарий от Sigrlami

переводи лишним не будет, но, пожалуйста, перед выкладыванеим на хабр/лор/(личный блог, если его читают многие), попроси одного-двух человек кто в теме оценить перевод. Просто, честно, читать язык напоминающий русский очень тяжело. Хотя это и компенсируется тем, что мало кто действительно читает статью (судя по хабру и лору), но лучше делать более качественные вещи. В общем-то неповезло и в том, что данная статья оказалась не самой удачной, а вообще линзы требуют интересных обучающих материалов, ибо мощная штука, но чтобы её изучить нужно или сидеть на #haskell-lens или рыться по haddock.

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

qnikst ★★★★★
() автор топика
Последнее исправление: qnikst (всего исправлений: 1)

Омерзительная статья.

Miguel ★★★★★
()
Ответ на: комментарий от qnikst

да и по классу да интерфейсу на каждую из возможностей линз

Ну да. Функция Haskell = Класс Явы. В Яве «всё есть класс/объект».

да и пока в яве нету сахара для лямбд это всё равно не будет юзабельно.

Ява без IDE в принципе неюзабельна. Могу в IDE добавить кнопку «сгенерировать лямбду», которая будет запрашивать параметры и код тела и создавать кусок кода типа:

   new Lambda1234 {
      public <тип результата> run(<типы параметров>) {
         <тело лямбды>
      }
    }()

:-)

monk ★★★★★
()
Ответ на: комментарий от monk

Ява без IDE в принципе неюзабельна. Могу в IDE добавить кнопку «сгенерировать лямбду», которая будет запрашивать параметры и код тела и создавать кусок кода типа:

это релевантно для write-only языка, судя по моей памяти о яве, это не такой язык.

Впрочем все справляются и так и индустрию в яве в целом устраивает текущее положение дел.

qnikst ★★★★★
() автор топика
Ответ на: комментарий от Bad_ptr

Игры вокруг нас!
работа — игра,

А то!

http://hh.ru/vacancy/8566257

Ключевые слова: геймификация обучения, виртуальные симуляторы, RPG-обучение, мобильные приложения и другие инновации.

Deleted
()
Последнее исправление: fargred (всего исправлений: 1)
Ответ на: комментарий от qnikst

это релевантно для write-only языка, судя по моей памяти о яве, это не такой язык.

Она скорее read-only... В смысле, написать что-то руками в vim на Java — сущий ад, слишком много bpoilerplate'а. В последних версиях IDE есть замечательные кнопки «Добавить класс» и «Добавить метод», «Добавить поле класса» (создаёт геттеры/сеттеры). На этом фоне кнопка «Вставить лямбду» будет воплне органична. Другое дело, что при наличии foreach оно никому не надо, это да. А для callback'а лучше нормальный класс написать.

write-only скорее Haskell. На нём легко писать, но через пару дней сам долго втыкаешь что делает, например

app req = do
    (requestBody req $$ consume) >>= liftIO . print
    return $ ResponseBuilder status200 [] (fromByteString "PONG")
Чем-то SQL напоминает. Там тоже промежуточных данных нет и порядок выполнения запроса неочевиден.

monk ★★★★★
()
Ответ на: комментарий от monk

Она скорее read-only...

оно начинает быстро не помещаться в экран в итоге адекватная навигация только по менюшкам в IDE.

write-only скорее Haskell. На нём легко писать, но через пару дней сам долго втыкаешь что делает, например

распарсил меньше, чем 3 сек (время чтения, плюс 2 строку просмотрел 2 раза), учитывая, что с первого взгляда понял домен и используемые либы :). Хотя если много играться с point-free то writeonly легко писать.

qnikst ★★★★★
() автор топика
Ответ на: комментарий от ranka-lee

в линзах и моданах деньги не лежат, но получать деньги когда пишешь на haskell реально даже вполне среднему программисту типа меня.

qnikst ★★★★★
() автор топика
Ответ на: комментарий от qnikst

плюс 2 строку просмотрел 2 раза

Я это и имел в виду. Обычно, когда читаешь текст программы, то движешься о тексту вниз и постепенно строишь себе в памяти алгоритм. А с Хаскелем на таких строчках у меня «срыв кэша» происходит. Если 2-3 на функцию встретилось, то приходится функцию перечитывать :-(

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

>>> over each Char.toUpper ("hello"^.Text.packed)
"HELLO"

Вообще, все эти линзы мне напоминают iterate из Common Lisp или for из Racket. Причём, у for и iterate есть бонус: они позволяют ходить по нескольким последовательностям одновременно (или я в линзах это не нашёл).

monk ★★★★★
()
Ответ на: комментарий от monk

Я это и имел в виду. Обычно, когда читаешь текст программы, то движешься о тексту вниз и постепенно строишь себе в памяти алгоритм. А с Хаскелем на таких строчках у меня «срыв кэша» происходит.

нескажи, во всех циклах и ифах-кейсах я перепроверяю что где используется, так что это минимум нормально.

Вообще, все эти линзы мне напоминают iterate из Common Lisp или for из Racket. Причём, у for и iterate есть бонус: они позволяют ходить по нескольким последовательностям одновременно (или я в линзах это не нашёл)

если я правильно понимаю, то в линзах явно такого нет. вообще для хождения по структурам есть зиппер-ы (в линзах вроде они тоже были), с ними можно ходить по нескольких последовательностям, объединив несколько структур в одну (без потерь в производительности и практически без лишних накладных расходов).

qnikst ★★★★★
() автор топика
Ответ на: комментарий от qnikst

вообще для хождения по структурам есть зиппер-ы

Я снова перестал понимать. Какую задачу решают линзы? Можно сформулировать?

monk ★★★★★
()
Ответ на: комментарий от monk

(ещё раз напомню, что я не специалист в этом направлении)

Линзы решают проблему удобного доступа и модификации полей во вложенных структурах. Самая продвинутая реализация - lens во-первых предоставляет много способов создать линзы для структуры, там есть вариант через прямой доступ и через изоморфизмы (я не разобрался, где это удобно применять). Ещё туда входят модули упрощающие работы с такими структурами такие как: level, prism, zoom...

Так же в пакет входят близкие решения:

* зипперы - подход для _произвольного_ перемещения и модификации неизменяемой структуры данных.

В отличии от zipper-ов «обычное» апи имеет только метод traverse (и схожие), который проходит по заданному пути.

Я выделил зипперы отдельно, т.к. это более старый подход, чем линзы, по которому написано немало статей, даже в «Хацкель во имя добра» кусок Олегостатьи попал. Хотя, естественно, максимальный эффект будет при объединении подходов.

qnikst ★★★★★
() автор топика
Ответ на: комментарий от qnikst

Линзы решают проблему удобного доступа и модификации полей во вложенных структурах.

Тогда они проигрывают схеме object.x.y.z := object.a.b.c + 1 (в хаскеле с поправкой на <- вместо :=). В том смысле, что кода приходится писать больше и он менее очевиден.

А если в «вложенных структурах в последовательности структур», то сравниваем с iterate...

monk ★★★★★
()
Ответ на: комментарий от monk

Тогда они проигрывают схеме object.x.y.z := object.a.b.c + 1 (в хаскеле с поправкой на <- вместо :=). В том смысле, что кода приходится писать больше и он менее очевиден.

ты хотел сказать схеме:

object1 := object.copy()
object1.x.y.z = object.a.b.c + 1

да проигрывают, вместо . придётся использовать аж ^. и %= вместо =. зато можно написать цепочку налогичную (object.foo().bar(5).baz), где foo/bar/baz возвращают объект того же тип объекта, но без необходимости фиксировать таким образом интерфейс.

let obj' = obj & over (x.y.z) (obj^.a^.b^.c + 1)
               & over (k.l.m) (obj^.a^.b^.g + 2)

Жалко у меня «реальные» примеры потерялись где-то.

А если в «вложенных структурах в последовательности структур», то сравниваем с iterate...

есть общая документация, а лучше примеры где-нибудь? Хочется видеть fold-ы, map-ы, подуровни, zoom.

qnikst ★★★★★
() автор топика
Ответ на: комментарий от qnikst

Просто неестественно. Здесь шляпка, здесь не шляпка, ... Почему не:

let obj' = runSet obj do
   x.y.z <- a.b.c + 1
   k.l.m <- a.b.g + 2
?

Хочется видеть fold-ы, map-ы, подуровни, zoom.

Тогда лучше Racket'овский вариант. iterate больше на императивное изменение данных заточен.

fold:

> (for/fold ([len 0])
            ([chapter '("Intro" "Conclusion")])
    (+ len (string-length chapter)))
15

map:

> (for/list ([i (in-naturals 1)]
             [chapter '("Intro" "Details" "Conclusion")]
             #:when (odd? i))
    chapter)
'("Intro" "Conclusion")

(for*/list ([book '("Guide" "Story" "Reference")]
            [chapter '("Intro" "Details" "Conclusion")])
    #:break (and (equal? book "Story")
                 (equal? chapter "Conclusion"))
    (format "~a ~a" book chapter))
'("Guide Intro" "Guide Details" "Guide Conclusion" "Story Intro" "Story Details")

zoom — я так понимаю, что будет простой фильтр на список. Подуровни, думаю, тоже...

В общем, напиши на линзах пример, я напишу альтернативу.

monk ★★★★★
()
Ответ на: комментарий от monk

Просто неестественно. Здесь шляпка, здесь не шляпка, ... Почему не:

потому, что написанная монада не имеет смысла, и не является composable.

zoom — я так понимаю, что будет простой фильтр на список.

это скорее аналог with в паскале (и java), когда ты внутри zoom работаешь с подуровнем без необходимости его каждый раз указывать.

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

data Book = Book { chapter :: [String] }

foldl (\i x-> i + length x) 0 (chapter (Book [«Intro», «Conclusion»])

foldr (\(k,x) i -> if odd k then i else (x:i)) [] $ zip [0..] (chapter (Book [«Intro», «Details», «Conclusion»]))

takeWhile (/= («Story»,«Conclusion»)) $ liftM2 (,) [«Guide»,«Story»,«Reference»] [«Intro»,«Details»,«Conclusion»]

qnikst ★★★★★
() автор топика
Ответ на: комментарий от ranka-lee

линзы - в зависимости от использования или просто функции или замыкания, большая часть работы прододится в compile time, для зипперов создается биективная структура, но с удобными свойствами. из минусов, что под каждую структуру нужно находить своё подходящее отображение, см. пример ниже. Плюс поскольку haskell ленивый иммутабельный язык, то активно используется COW и ленивость, в следствии чего расход памяти снижается.

Простейший пример зипперов для списка. Список в haskell это это ленивый singli-linked-list. Вместо списка делаем:

data ZipperList = ZipperList [a] (Maybe a) [a]

где первый список это начало списка задом наперёд, потом текущий элемент (если есть), потом конец списка в правильной последовательности. Соот. перемещение по списку это O(1) по времени и месту.

отображение из List -> ZipperList O(1) по памяти и O(1) по времени, отображение назад O(размер-первой-части) по памяти и времени, в случае если списки вычислены.

Я вылетел из контекста, поэтому не понял про какие именно стукруты речь, но надеюсь, что на вопрос ответил. А все неоптимизированные структуры живут в куче.

qnikst ★★★★★
() автор топика
Последнее исправление: qnikst (всего исправлений: 1)
Ответ на: комментарий от ranka-lee

пожалуйста скопируй интересующую часть, просто тут больно много всего разного, что лежит по разному лежит в памяти, и в описывать картину в целом я задолбаюсь и не осилю, поэтому очень прошу конкретизировать вопрос, какая именно красота. Тогда я попытаюсь расписать это.

qnikst ★★★★★
() автор топика
Ответ на: комментарий от qnikst

Как все эти хитрые структуры физически лежат в байтах памяти и как я могу это контролировать. У меня, как у графического программиста, на структуры вроде «связный список» или «дерево» начинает дёргаться глаз.

ranka-lee
()
Ответ на: комментарий от qnikst

я не увидел ничего, для чего нужны были бы линзы

Я как раз пытаюсь понять «для чего нужны были бы линзы». В смысле, напиши линзу, которую реализовать на Lisp/Java было бы громоздко и некрасиво. А то у меня ощущение блаб-парадокса: если чем-то не пользовался, то кажется что оно не надо или совпадает с чем-то привычным (я отобразил линзы на foreach + аксессоры).

monk ★★★★★
()
Ответ на: комментарий от monk

своих юзкейсов добавить не могу, ибо там их не пользую. Другие примеры можно найти например тут:

http://hackage.haskell.org/package/tables <- напр. тут

или тут http://packdeps.haskellers.com/reverse/lens

лично я использовал линзы как продвинутые аксессоры, но это не то, что минимальный используемый функционал, а даже меньше минимума :)

qnikst ★★★★★
() автор топика
Ответ на: комментарий от ranka-lee

какие «эти»? линзы, зипперы, списки, я не хочу пересказывать всю работу rts haskell (тем более несколько раз ошибусь).

qnikst ★★★★★
() автор топика
Ответ на: комментарий от qnikst

Любые. Я например хочу сказать «эту фигню я читаю последовательно» и мне надо чтобы байтики тоже лежали последовательно. По идее ваш хаскель должен уметь знать какими «линзами» данные читаются и соответственно заранее их реорганизовывать.

Если нет вообще никакого контроля над тем как двигаются байтики - то язык практически бесполезен.

ranka-lee
()
Ответ на: комментарий от ranka-lee

Любые

тогда читай начиная отсюда: http://ghc.haskell.org/trac/ghc/wiki/Commentary

Я например хочу сказать «эту фигню я читаю последовательно» и мне надо чтобы байтики тоже лежали последовательно

чьи байтики лежали?

По идее ваш хаскель должен уметь знать какими «линзами» данные читаются и соответственно заранее их реорганизовывать.

я даже не знаю что на это можно осмысленно ответить..

Если нет вообще никакого контроля над тем как двигаются байтики - то язык практически бесполезен.

есть, но линзы тут ни при чем.

..мне кажется это бесполезная трата времени с обоих сторон

qnikst ★★★★★
() автор топика
Ответ на: комментарий от qnikst

чьи байтики лежали?

Данных. Вы можете сделать какие угодно хитрые математические структуры, но они всё равно будут байтами в памяти.

даже не знаю что на это можно осмысленно ответить..

А надо. Это один из критически важных вопросов без которого никак нельзя достичь нормальной производительности.

есть, но линзы тут ни при чем.

Какие? Как я могу сказать «хочу чтобы эти данные лежали в памяти друг за другом»? В жабе я этого сказать не могу если, в C/C++ могу.

ranka-lee
()
Ответ на: комментарий от qnikst

http://hackage.haskell.org/package/tables <- напр. тут

Здесь всё записанный хитрым образом map+filter.

Например,

>>> test ^. with (length . fooBar) (<=) 3
fromList [ Foo {fooId = 1, fooBar = "One", fooBaz = 1.0}
         , Foo {fooId = 2, fooBar = "Two", fooBaz = 2.0} ]

равносильно

(filter (lambda (x) (<= (string-length (fooBar x)) 3)) test)

http://hackage.haskell.org/package/lens

Здесь много. Но тоже ощущение, что голый сахар. Или я не знаю, что искать (часть конструкций сходу не понял, мог пропустить).

monk ★★★★★
()
Ответ на: комментарий от ranka-lee

в C/C++ могу.

На самом деле и в C не сможешь. Если только не пишешь ОС. Так как всё, что ты можеьш потребовать — чтобы адреса в памяти процесса для этих данных были подряд. А потом ОС побъёт их на страницы и как-нибудь разместит :-)

monk ★★★★★
()
Ответ на: комментарий от monk

То что оно побьёт на страницы это уже вопрос третьестепенный, главное что контроллеру памяти не надо скакать туда-сюда на каждый чих.

ranka-lee
()
Ответ на: комментарий от monk

Или я не знаю, что искать

Поясню. Если мне надо объяснить C++-нику зачем нужны лямбды, то покажу в качестве примера вывод коллекции через foreach. Хотя да, без лямбд можно обойтись (везде, где нужна неименованая функция, можно использовать именованую).

Если нужно объяснить полезность продолжений — есть классический пример с сравнением двух коллекций для которых есть map. Ну или возможность реализовать итератор через тот же map.

Хочу такой же пример для линз. Пока всё, на что натыкаюсь — либо аксессоры, либо map+filter. То есть вне Хаскелла не нужно (я понимаю, что в Хаскелле записать a.b.c += 1 без линз слегка неудобно).

monk ★★★★★
()
Ответ на: комментарий от ranka-lee

Так Хаскелл просто расположит «рядом используемые» данные рядом в памяти. Не надо ему ничего говорить. А дальше как с кэшем повезёт. Или думаешь кэшу не всё равно в каком порядке страницы из памяти подгружать?

monk ★★★★★
()
Ответ на: комментарий от ranka-lee

Данных. Вы можете сделать какие угодно хитрые математические структуры, но они всё равно будут байтами в памяти.

если ты хочешь поговорить о модели работы с памятью RTS haskell (будем говорить только по GHC), то это отдельная достаточно большая тема тема для знакомого с языком, хотя и не являющаяся хаками и rocket science. Поскольку тред не об этом, то я позволю себе ограничиться ключевыми словами.

В haskell есть несколько типов данных primitime, unboxed, boxed, lifted. Первые соотв машинным словам, для последних возможен undefined и ленивость. Данные могут быть как строгими, так и ленивыми.

Для прямой работы с памятью есть как операции, так и вспомогательные типы Array#, Buffer.

Данные могут быть pinned (GC их не будет двигать) и unpinned (GC при сборках может перемещать данные). При желании можно делать типизированную работу с памятью.

Каждый из абзацев выше тянет на полчаса обсуждения с примерами использования и объяснения почему это вообще не нужно пока не доказано обратное :)

Главное не забывать, что haskell по умолчанию immutable язык и это не случайно, в т.ч. и с т.зр. производительности, и некоторые хотелки уровня «как в Си» тут не очень уместны.

А надо.

осмысленно можно ответить на любой осмысленный вопрос хорошо сформулированный вопрос.

Это один из критически важных вопросов без которого никак нельзя достичь нормальной производительности.

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

В жабе я этого сказать не могу если, в C/C++ могу.

можешь, но обычно это не нужно.

А ещё в haskell есть полноценный FFI и дешевый FFI через C-- и для продвинутых возможность добавлять PrimOp.

P.S. не слишком много key^Wbuzz word-ов?

qnikst ★★★★★
() автор топика
Ответ на: комментарий от monk

Здесь много. Но тоже ощущение, что голый сахар. Или я не знаю, что искать (часть конструкций сходу не понял, мог пропустить).

не туда ссылку дал, хотел на обратные зависимости lens. Сам этот пакет это собственно и есть линзы, они сложные я не осилил.

Впрочем автор статьи в ТС-посте обещал через какое-то время пост про его real-live использование линз написать, так что можно подождать.

Не я готов назвать killer-features линз в сравнении с другими языками.

qnikst ★★★★★
() автор топика

И поле этого кто-то рассказывает что perl - write only язык? X-D

gear ★★★
()
Ответ на: комментарий от ranka-lee

ты можешь сделать так, что в виртуальной памяти данные будут как тебе надо. Однако в подавляющем большинстве случаев тебе это не надо.

qnikst ★★★★★
() автор топика

Я неправ, или там так и не появилось вменяемого определения? «Линзы повзволяют», «лизнзы могут», «с линзами мы так близки к». ЧЗХ?

cdshines ★★★★★
()
Ответ на: комментарий от qnikst

можешь, но обычно это не нужно.

Мне нужно всегда.

осмысленно можно ответить на любой осмысленный вопрос хорошо сформулированный вопрос.

Могу ли я гарантировать что моя структура данных будет лежать в памяти машины в виде большого линейного блоба? Так понятно?

ranka-lee
()
Ответ на: комментарий от ranka-lee

Мне нужно всегда.

или у тебя очень узкий юзкейс или ты ошибаешься, впрочем можешь сказать свой юзкейс.

Могу ли я гарантировать что моя структура данных будет лежать в памяти машины в виде большого линейного блоба? Так понятно?

я уже ответил на этот вопрос - да можешь

qnikst ★★★★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.