LINUX.ORG.RU
ФорумTalks

лямбды в новых язычках - PR или реальные полезняшки?

 , ,


7

7

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

Ну что есть lambda в каком-нибудь lisp я представляю и даже понимаю зачем оно и как им пользоваться. В lisp'е. А что имеется ввиду под «лямбдой» например, в C#?

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

Только чтобы это не было аналогом перлового однострочника типа

perl -e 'print sub{ $_[0] + $_[1]; }->(1,2)."\n";'
ибо в этом никаких новшеств и преимуществ нету.

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

★★★★★

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

А на С++ совсем другая программа

программа - одна и та же ) я понимаю, что ты хочешь сказать, и согласен; я за то, что всему свое место, простым задачам - простое решение, вот Ritmic пытался применить свои идеи к простому коду, и получилось у него два варианта - один откровенно притянутый за уши и медленный, и второй - нечитабельный ( (sum* 1 1 n *) -для меня по крайней мере это не очевидно, и мне пришлось бы идти и читать код этой функции ), и даже нерабочий

Если переписать с генераторами, то тоже будет быстрее и тоньше, конечно, на то он и C++, но писать будешь не одну строчку а over 500.

#include <gmpxx.h>
#include <iostream>

struct factorials
{
    factorials( mpz_class n=0 ) { e=n; }
    mpz_class n=1, i=1, e;

    factorials& begin() { return *this; }
    factorials& end() { return *this; }
 
    bool operator!=(const factorials&) const { return e==0 || i<=e; }
    void operator++() { n*=++i; }
    mpz_class& operator*() { return n; }
};


int main() {
    for( auto i: factorials() )
        std::cout << i << '\n';
}

да ладно

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

Аргументы у функции не мапом. Все также.

Покажи квазицитирование в эти [ ] у defn

«Квазицитирование» это из хаскеля?

Не понял, но догадываюсь, что ты имеешь в виду.

(defn f [a coll]
  (let [x (first coll)
         y (second coll)]
    ...)

Упрощение:

(defn f [a [x y]]
 ....)

(def g [a mmap]
  (let [x (:key1 mmap)
         y (:key2 mmap]
  ...)

Упрощение

(def g [a {x :key1 y :key2}]
   ...)

Или, если имена параметров совпадают с именами ключей

(def g [a {:keys [x y]}]
   ...)

Еще добавлю, что деструктуризация при связывании работает в любом связывании: let, binding, doseq, for и т.д.

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

да ладно

время работы и потребление памяти не изменилось - 196Кб и 2.8сек на выдачу данных в stdout

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

Но это же чисто специфика CL, а не всех лиспов, не правда ли?

Я заметь отвечал на

создавался с учетом недостатков лиспов, особенно CL.

Раз уж CL был пртянут (за уши) то соответсвенно всплывают и все его возможности

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

Имелось ввиду что эти недостатки говорят, а не аномные аналитики.

Я тебя понимаю. ... Это от незнания матчасти clojure.

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

Ты еще не перечислил, что тебе не понравилось в clojure?

java-центричность что для меня сомнительная ценность при наличии уже сущесвующего CL, эмоцианальное выпячивание"крутых фич" совместно с вынесением в ненужное CL-ного. НеЭволюционность скачка от CL.

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

Если ты потрудишься и поразбираешься,

То увижу тот же урезок clos. Я интересовался предметом и мнение имею не потому что «не читал».

Я лишь отмечаю факт что если бы мы имели эволюционный вариант развития то протоколов бы не появилось, они были данностью просто еще одним небольшим расширением clos/mop.

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

Честно говоря, подобная критика звучит не очень убедительно.

Это не критика, это то что не дает называть лиспом с формально-опредлительной точки зрения.

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

Матчасть я имхо ограниченно знаю.

Тогда скажи конкретно, чего тебе не хватает в clojure, кроме сигналов?

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

Как можно делать такое «весомое» суждение и говорить при этом «Матчасть я имхо ограниченно знаю.»?

Я преимущества clojure уже тебе отписывал лямбды в новых язычках - PR или реальные полезняшки? (комментарий)

Добавь сюда collection comprehenoin, деструктуризацию и прочие вещи.

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

Это не критика, это то что не дает называть лиспом с формально-опредлительной точки зрения.

А хотелось бы критики!!!111 :D Конструктивной, конечно же.

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

Это не критика, это то что не дает называть лиспом с формально-опредлительной точки зрения.

Дайте формальное определение лиспу. После этого можно уже можно будет на что-то опираться. До этого вы приводили CL-специфичные вещи (CLOS, сигналы).

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

а цикл 1..N с разными переменными и условиями - не общий код, ну это ж очевидно

просто праздник какой-то! Давненько таких петросянов не встречал!

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

Тогда скажи конкретно, чего тебе не хватает в clojure, кроме сигналов?

Мне уже хватает sbcl/ecl и abcl если внезапно понадобится. В первую очередь мне нужна инфраструктура не забетонированя явой. К clos опять же привыкаешь. А то что предъявляется как преимущества не предсталяется мне определяющим, не цепляет.

Я не оцениваю язык, я на clojure не пишу. Я лишь не соглашаюсь с утверждением что clojure исправляет какие-то недостатки CL, наоборот оно ему глубоко паралельно и просто игнорирует вполне устоявшиеся и признаные полезными в CL области. Сами по себе рассуждения по поводу лучшести мне достаточно фиолетовы.

говорить при этом «Матчасть я имхо ограниченно знаю.»

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

Как можно делать такое «весомое» суждение

Оно не «весомое», оно моё:) Просьба не передергивать.

Я преимущества clojure уже тебе отписывал лямбды в новых язычках - PR или реальные полезняшки? (комментарий)

1. лисп остался 2. опциональгная ленивость, коллекции 3. прекрасная интеграцию с могучей платформой, 4. чистота функций и нативных коллекций 5. киллер фича: механизмы для координации доступа к данным в многопоточных приложениях

Преимущества в таких формулировках это «космические корабли бороздящие пространство большео театра»

3. прекрасная интеграцию с могучей платформой

3. Про насколько мне нужна «могучая» платформа которая прилагается принудительно я уже говорил.

1. лисп остался

Так же как и другие лиспы. Ничего нового.

5. киллер фича: механизмы для координации доступа к данным в многопоточных приложенияx

Они не единствено возможные, согласись. Есть хорошо, нет фиг с ним.

4. чистота функций и нативных коллекций

ИМХО CL все таки не C поэтому это не слишком актуально

2. опциональгная ленивость, коллекции

Для этого написали принципиально новый язык и рассказвли про недостки CL, офигеть.

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

Дайте формальное определение лиспу. После этого можно уже можно будет на что-то опираться.

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

Те два отмеченые мной момента одинаковы как миниум для CL и схемы, что дает право возволить в канонический признак настоящего лиспа. Чуть позже я гляну в clojure-вскую спеку и или перефразирую опираясь на первоисточник или признаю ошибку. Это все исключтельно истины ради. Дальнейший поиск предмета спора для опры мне не интересен.

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

да ладно

Ну так где обобщённые последовательности, map, reduce и т.п. для них с произвольными std::function? То есть всё это или это. Там это не вполне то же самое что похожие функции для std::list, так как в случае бесконечных данных превращается в итеративные линейные по времени и константные по памяти алгоритмы (в хаскеле к ним, к тому же, применяется list fusion).

Например

import Data.Ratio

-- | ℕ⁺ ≡ ℕ \ {0}
naturals :: [Integer]
naturals = [1 ..]

-- | P ≡ { ∏ n : n ∈ ℕ⁺ }
factorials :: [Integer]
factorials = scanl1 (*) naturals

-- | S ≡ { ∑ n : n ∈ ℕ⁺ }
triangulars :: [Integer]
triangulars = scanl1 (+) naturals

-- | S|P ≡ { n : (n, p, s) ∈ ℕ⁺ × P × S, s | p }
factorialsDivisibleByTriangulars :: [Integer]
factorialsDivisibleByTriangulars
  = map fst $ filter ((== 1) . denominator . snd)
  $ zipWith3 (\n p s -> (n, p % s)) naturals factorials triangulars

правда ли, что это множество строго включает в себя множество простых чисел без двойки?

-- | ℙ ≡ { p : ∄ (f : ℕ⁺ \ {1, p}) f | p }
primes :: [Integer]
primes = 2 : 3 : filter (noDivs $ tail primes) [5, 7 ..] where
  noDivs fs n = foldr (\f a -> f * f > n || (rem n f /= 0 && a)) True fs

-- | L ≡ ∃ (p : ℙ \ {2}) . p ∉ S|P
--  ¬L ≡ ∀ (p : ℙ \ {2}) . p ∈ S|P
lemma :: Bool
lemma = any (not . (`elem` factorialsDivisibleByTriangulars)) $ tail primes

-- | Can't (constructively) prove L, so that ¬L holds ;)
main :: IO ()
main = lemma `seq` putStrLn "Decidable, so that L holds."

тратит время на одном ядре и медленно ест память (хотя зачем?), но молчит.

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

Основные отличия от других лиспов - http://clojure.org/lisps.

Это про то что убрали или изменили, там не говорится что добавили новое и из-за чего обычно выбирают clojure (java interop, agents, message passing, stm, laziness, immutability, metadata, shared & extensible primitive types, multimethods, hygiene, pattern-matching, что ещё не вспомнил?).

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

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

Какие области?

3. прекрасная интеграцию с могучей платформой

Про насколько мне нужна «могучая» платформа которая прилагается принудительно я уже говорил.

Это огромный плюс для использования языка в инфраструктуре, где уже есть джава. Благодаря отчасти этому, clojure afair уже чаще используется стартапами и в существующих проектах, чем CL (еще раз, это лишь мое наблюдение, т.к. я слежу за рынком труда по лиспу вообще).

5. киллер фича: механизмы для координации доступа к данным в многопоточных приложенияx

Они не единствено возможные, согласись. Есть хорошо, нет фиг с ним.

Вы потрудитесь сначала все-таки ознакомиться с мат. частью. Например, тут http://my.safaribooksonline.com/book/programming/clojure/9781935182641/mutati...
http://www.infoq.com/presentations/Value-Identity-State-Rich-Hickey.
http://blip.tv/clojure/clojure-concurrency-819147

Я использую в своих проектах и могу с уверенностю сказать, что это реально киллер фича.

Еще раз советую почитать изучить по ссылкам, прежде чем что-то сказать.

4. чистота функций и нативных коллекций

ИМХО CL все таки не C поэтому это не слишком актуально

В CL тяжело достижима такая же работа с иммутабельными коллекциями и чистыми функциями, как в clojure.

В инете искать по фразе «clojure persistent data structure». Также есть одно из видео по этой теме http://www.infoq.com/presentations/Value-Identity-State-Rich-Hickey.

2. опциональгная ленивость, коллекции

Для этого написали принципиально новый язык и рассказвли про недостки CL, офигеть.

Т.е. ты не согласен, что у CL недостатки?

- Провоцирует по-умолчанию писать код, реально меняющий данные? Все структуры данных CL мутабельны. Работать с ними иммутабельно не эффективно из-за алгоритмического оверхеда и оверхеда по памяти.

- Из-за отсутствия чистоты не так эффективна с точки зрения затрат усилий работа при создании мультипоточных приложений.

- Из-за отсутствия map/list comprehension-а много синтаксического шума при работе с коллекциями.

- Lisp-2 - для функционального языка это генетическая ошибка.

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

Дайте формальное определение лиспу. После этого можно уже можно будет на что-то опираться.

До сих пор так и не было ничего сказано о том как и какие недостатки CL исправляет clojure. Это кастельно бузины и киева.
Те два отмеченые мной момента одинаковы как миниум для CL и схемы, что дает право возволить в канонический признак настоящего лиспа. Чуть позже я гляну в clojure-вскую спеку и или перефразирую опираясь на первоисточник или признаю ошибку. Это все исключтельно истины ради. Дальнейший поиск предмета спора для опры мне не интересен.

Не увиливайте. Вы сами тут лямбды в новых язычках - PR или реальные полезняшки? (комментарий) сказали «Это не критика, это то что не дает называть лиспом с формально-опредлительной точки зрения.» Что предполагает, что у вас есть формальное определение.

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

Не знание мат. части обсуждаемых вещей, непонимание целей, для чего и как созданы обсуждаемые вещи, выпадки с умным видом «у меня в X все отлично, а у вас в Y фигня напридумана». Как печально видеть еще одного такого.

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

а чем это не reduce?

Вполне reduce.

Но покажи лучше как partial_sum заставить работать с infinite_nats_seq -> infinite_facs_seq. У меня g++ плюются полотнами, clang++ плюются полотнами и падает сегфолтом.

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

- Провоцирует по-умолчанию писать код, реально меняющий данные? Все структуры данных CL мутабельны. Работать с ними иммутабельно не эффективно из-за алгоритмического оверхеда и оверхеда по памяти.

- Из-за отсутствия чистоты не так эффективна с точки зрения затрат усилий работа при создании мультипоточных приложений.

- Из-за отсутствия map/list comprehension-а много синтаксического шума при работе с коллекциями.

- Lisp-2 - для функционального языка это генетическая ошибка.

Ничего из этого напрямую к CL не относится. Это фактически подверждение моего тезиса о том что главнейший недостаток CL в том что он не Clojure.

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

входы девайса это список, и выходы девайса тоже список

Я не в теме, поэтому спрошу - списки чего?

Это о «дрыганье ногами», список - поступающих сигналов. Схемотехника: на входе набор сигналов на выходе >=1 сигнал.

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

Справедливости ради, я бы отметил, что для программирования FPGA плохо подходит динамически типизированный язык, как целевой. Область вполне себе сформировавшаяся, все, начиная от сигналов, заканчивая комплексами модулей и интерфейсами между плисом и кристаллом можно, и я бы сказал нужно, статически типизировать. CL используется для генерации такого статически типизированного кода, но по моему мнению это из-за того, что SV и VHDL - г-но.

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

непонимание целей, для чего и как созданы обсуждаемые вещи,

Очень забавное обвинение учитывая что вы тоже этот вопрос освятили очень поверхностно ограничась общими рассуждениями об иммутабельности. Про ва список недостатков CL я уже говорил выше

выпадки с умным видом «у меня в X все отлично, а у вас в Y фигня напридумана»

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

Как печально видеть еще одного такого.

Взаимно. Раз дошли до перехода на личности, то нашу дисскусию клоунов отставших от цирка я пожалуй закончу.

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

Использование лиспа для кодогенерации встречалось для FPGA, но это настолько девайсоспецифично (даже не вендорспецифично) сделано, что реюз этого toolchain для другого девайса невозможен практически. Уж не говоря о том, что это всё - через жопу.

Обычно производители предоставляют инструменты (зачастую очень сложные и сильно проприетарные) для работы и костомизации своих FPGA. Синтезаторы в том числе. Описание аппаратуры - вполне себе сформированный домейн (другое дело, что популярные языки описания аппаратуры редки отстой) и кодогенерация была бы уместна не для тех задач, которыми обычно занимается HDL, а, например, для синтеза hdl высокого уровня -> hdl низкого уровня по открытым спекам (которых по факту сейчас не существует вообще) для убер-девайса.

Программа на лиспе - список, который принимает на входе список и выдаёт тоже список.

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

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

Это про то что убрали или изменили, там не говорится что добавили новое и из-за чего обычно выбирают clojure (java interop, agents, message passing, stm, laziness, immutability, metadata, shared & extensible primitive types, multimethods, hygiene, pattern-matching, что ещё не вспомнил?).

Сори, не верно выразился, мне просто было бы интересно пообсуждать решение, обозначенные в документе по ссылке. Относительно тех фич, что перечислили вы - большинство из них безусловный позитив (спорными будут пожалуй только java interop и hygiene вообще и конкретная реализация идей multimethods, metadata, immutability в частности). Хотя, признаюсь, я подробно clojure не смотрел, поэтому возможно и предубеждения :(

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

Как это не относится? CL действительно lisp-2, в нем нет искаробочно иммутабельных типов и их введение потребует как минимум отдельной библиотеки.

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

Схемотехника: на входе набор сигналов на выходе >=1 сигнал.

Начинаю вспоминать 5 главу SICP. Но это же просто какие-то специфичные кортежи которые никак не связаны с тем что называется «списками» в лиспе (cons-ы).

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

Как это не относится?

CL действительно lisp-2,

Что означает что он будет по другому вызывать и создавать функции. Разновидностей которых в CL будет чуть побольше. Но его позиционирование относительно ФП по сравнению с lisp-1 не изменится.

в нем нет искаробочно иммутабельных типов

Полюбопытствуйте для примера про недеструктивные операции над списками. И такая очевидная вещь как потоки.

их введение потребует как минимум отдельной библиотеки.

И в чем проблема? Это естественый процесс когда фичи языка вводятся библиотекой. Он таким создан.

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

CL действительно lisp-2,

Что означает что он будет по другому вызывать и создавать функции.

Да, именно это и означает.

Но его позиционирование относительно ФП по сравнению с lisp-1 не изменится.

Позиционирование имеет мало отношения к удобству применения.

в нем нет искаробочно иммутабельных типов

Полюбопытствуйте для примера про недеструктивные операции над списками.

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

И такая очевидная вещь как потоки.

Поясните мысль?

их введение потребует как минимум отдельной библиотеки.

И в чем проблема? Это естественый процесс когда фичи языка вводятся библиотекой. Он таким создан.

Угу, выше вон и reduce на плюсах наблюдаем и boost с функциональным программированием, не особо впечатляет, знаете ли

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

- Провоцирует по-умолчанию писать код, реально меняющий данные? Все структуры данных CL мутабельны. Работать с ними иммутабельно не эффективно из-за алгоритмического оверхеда и оверхеда по памяти.
- Из-за отсутствия чистоты не так эффективна с точки зрения затрат усилий работа при создании мультипоточных приложений.
- Из-за отсутствия map/list comprehension-а много синтаксического шума при работе с коллекциями.
- Lisp-2 - для функционального языка это генетическая ошибка.

Ничего из этого напрямую к CL не относится. Это фактически подверждение моего тезиса о том что главнейший недостаток CL в том что он не Clojure.

Это все напрямую относится к CL. Видимо у тебя нет аргументов против этих недостатков.

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

java interop

Фича номер один же.

immutability

Фича номер два :) На неё завязана вся система stm, агентов, ссылок и сама философия языка.

Итого, Clojure имеет смысл как jvm (про .net не знаю) язык с определённой философией (которую нужно принимать или нет).

hygiene

Позволяет обойтись без gensym и прочих with-gensyms.

multimethods

Шире чем то что в CL наличием более общей диспетчеризации чем по class и по eql.

metadata

В других лиспах просто нет из коробки.

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

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

Не распарсил.

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

Поясните мысль?

Потоки представляют интерфейс и идиому для бронирования ног.

Угу, выше вон и reduce на плюсах наблюдаем и boost с функциональным программированием, не особо впечатляет, знаете ли

А не ровняйте божий дар с яичницей.

Можно сколько угодно рассуждать на тему, как не отстрелить себе ногу,

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

Но его позиционирование относительно ФП по сравнению с lisp-1 не изменится.

Позиционирование имеет мало отношения к удобству применения.

По моим наблюденям немалая часть рассуждающих об удобстве принципиально юзает funcall+lambda вместо flet по причинам мне не понятным. Это спор слижком доисторичен что бы быть осмысленым. Если кому-то хочется считать это недостатком, то я на тему спорить пожалуй не буду.

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

Видимо у тебя нет аргументов против этих недостатков.

Я вашу позицию о недостатках понял и не считаю ее осмысленой. Препираться о ней, увольте.

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

Не распарсил.

Если у обьекта запилено свойство someProperty, я могу сразу какой-нибудь obj.getSomeProperty засунуть в map, например, или мне придётся всё это в лямбду оборачивать исключительно только чтобы значение свойства взять?

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

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

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

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

Ага, туплю. Подводит привычка засовывать в Ruby атомы методов вместо честных лямбд — там-то это срабатывает.

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

Но покажи лучше как partial_sum заставить работать с infinite_nats_seq -> infinite_facs_seq

#include <algorithm>
#include <gmpxx.h>
#include <iostream>
using namespace std;

#define NEXT(...)   gen_type& operator++() { __VA_ARGS__; return *this; }
#define RETURN(...) T& operator*() { return __VA_ARGS__; }
#define WHILE(...)  bool operator!=(const gen_type&) const { return __VA_ARGS__; }

#define GENERATOR( name, ... )                                          \
    struct name : public iterator<forward_iterator_tag,T> {             \
        typedef name gen_type;                                          \
        __VA_ARGS__                                                     \
        name& begin() { return *this; }                                 \
        name& end() { return *this; }                                   \
        bool operator==(const name& ) const { return !(*this!=*this); } \
    };


template<class T=mpz_class>
GENERATOR( numbers,
    RETURN( i ) WHILE( n==0 || i<=n ) NEXT( ++i )
    numbers( T to=T() ) { i=T(1); n=to; }
    T i, n;
)

template<class T=mpz_class,class I=numbers<T>>
GENERATOR( factorials,
    RETURN( n ) WHILE( i!=i ) NEXT( ++i; n*=*i; )
    factorials( T to=T() ) { i=I(to); }
    T n=1;
    I i;
)

int main() {
    factorials<> f(5);
    mpz_class r[5];
    partial_sum( f.begin(), f.end(), r, multiplies<mpz_class>());
}

пока все еще 40 строк, а не over 500

П.С. сразу говорю - я б такое не стал использовать с С++ )

wota ★★
()
Ответ на: комментарий от wota
#include <algorithm>
#include <gmpxx.h>
#include <iostream>
using namespace std;

#define NEXT(...)   gen_type& operator++() { __VA_ARGS__; return *this; }
#define RETURN(...) T& operator*() { return __VA_ARGS__; }
#define WHILE(...)  bool operator!=(const gen_type&) const { return __VA_ARGS__; }

#define GENERATOR( name, ... )                                          \
    struct name : public iterator<forward_iterator_tag,T> {             \
        typedef name gen_type;                                          \
        __VA_ARGS__                                                     \
        name& begin() { return *this; }                                 \
        name& end() { return *this; }                                   \
        bool operator==(const name& ) const { return !(*this!=*this); } \
    };

template<class T=mpz_class>
GENERATOR( numbers,
    RETURN( i ) WHILE( n==0 || i<=n ) NEXT( ++i )
	numbers( T to=T() ) { i=T(1); n=to; }
    T i, n;
)

template<class T=mpz_class,class I=numbers<T>>
GENERATOR( factorials,
    RETURN( n ) WHILE( i!=i ) NEXT( ++i; n*=*i; )
    factorials( T to=T() ) { i=I(to); }
    T n=1;
	I i;
)

int main() {
    for( auto i: factorials<>() )
        std::cout << i << '\n';
}

все те же 2.8сек и 200Кб в ОЗУ

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

g++ - sorry, unimplemented: non-static data member initializers

clang++ - too many errors emitted, stopping now

А что за 5 в main? Условие про infinite не соблюдено?

И partial_sum нужен для того чтобы определить поток factorials через поток numbers, на cppreference есть пример, но он для конечного массива. Поток (stream / lazy stream) это такая абстракция бесконечных данных, если что.

пока все еще 40 строк, а не over 500

Я там подразумевал самописную библиотеку для ленивых потоков, стандартные средства всё-таки немного не про то.

я б такое не стал использовать с С++ )

Более того, у тебя один макрос использует имя введённое другим, даже в CL себе такого не позволяют в большинстве случаев :)

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

g++ - sorry, unimplemented: non-static data member initializers

у меня 4.7.2

clang++ - too many errors emitted, stopping now

3.1, на всякий случай - собирать с -std=c++11

А что за 5 в main? Условие про infinite не соблюдено?

соблюдено:

лямбды в новых язычках - PR или реальные полезняшки? (комментарий)

это опциональный параметр

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

это опциональный параметр

Это понятно, я про 5 в массиве под результат partial_sum. То есть вместо демонстрации преобразования поток -> поток с помощью partial_sum и других функций STL пока получается упражнение в создании отдельных генераторов, возможно с агрегацией. Поэтому мне кажется (пока что я не уверен), что STL не предоставляет необходимых средств для написания чего-либо в терминах ленивых потоков.

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

Это понятно, я про 5 в массиве под результат partial_sum.

можно и так:

list<mpz_class> l;
partial_sum( f.begin(), f.end(), back_insert_iterator<list<mpz_class>>(l), multiplies<mpz_class>());

но это всегда будет создавать новый список, что конечно не желательно

Поэтому мне кажется (пока что я не уверен), что STL не предоставляет необходимых средств для написания чего-либо в терминах ленивых потоков.

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

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

Я вашу позицию о недостатках понял и не считаю ее осмысленой.

Пример работы с hashtable в CL

(defparameter *my-hash* (make-hash-table))

(setf (gethash 'first-key *my-hash*) 'one)
(setf (gethash 'second-key *my-hash*) 'two)
(setf (gethash 'third-key *my-hash*) nil)
(setf (gethash nil *my-hash*) 'nil-value)

(defun print-hash-entry (key value)
  (format t "The value associated with the key ~S is ~S~%" key value))

(maphash #'print-hash-entry *my-hash*)

Против идентичного кода на clojure

(def my-map {:first-key 'one
             :second-key 'two
             :third-key 'three})

(def my-map (assoc my-map nil 'nil-value))

(defn print-map [[k v]]
  (printf "The value associated with the key %s is %s\n" k v))

(map print-map my-map)

Пример взят из The Common Lisp Cookbook http://cl-cookbook.sourceforge.net/hashes.html

Недостатки уже на таком тривиальноми примере:

  • Навязывание работы с изменением состояния (ричина в том, что я описывал выше).
  • Отсутствие collection comprehension (на примере с hashtable, где для инициализации потребовалось пройтись по всем ключам)
  • Нет общего между коллекциями (для hashtable отдельная функция maphash)

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

(let [my-map (assoc my-map nil 'nil-value)]
  (map (fn [[k v]]
         (printf "The value associated with the key %s is %s" k v))))

В CL мне для этого пришлось бы явно создавать второй hashtable, потом копировать туда старый. Но расход памяти под данные в этом случае увеличился бы в ДВА РАЗА.

Эти различия обнаруживаются уже на таком маленьком примере. Если расписывать все, что я уже перечислил выше с примерами, то получится, что в CL много недостатков, которые были убраны в clojure.

Теперь скажи мне, что это не недостатки, а фичи.

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

lisp-2 vs lisp-1

CL

(defun doubler (f)
    (lambda (x) (funcall f x x)))

(funcall (doubler #'+) 4)
=> 8

clojure

(defn doubler [f]
  (fn [x] (f x x)))

((doubler +) 4)
=> 8

No comments.

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