LINUX.ORG.RU

Perl 6 vs Python 3

 , ,


3

4

Дискач.

Чтобы писать утилиты и демоны например для десктопа. Допустим оставим в покое веб-девелопмент, там и так тесно. И забудем былое, Python 2, Perl 5 и связанные стереотипы.

P.S. Прошу не удалять за тупняк, я понимаю как это выглядит. Но тема то интересная

★★★★★

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

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

Мои глаза читают текст гайдов/примеров и видят: Рутина. Мозгу надо постоянно несколько «тиков» что бы подхватить контекст. Хотя наверно ещё не привык.

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

https://metacpan.org/release/AI-MXNet

https://metacpan.org/search?size=500&q=Telegram

Искать лень, не моя тема. Но думаешь что в том же torch, сборка которого зависит от perl, нельзя на перле сделать? Всё дергается элементарно. Ну, может не для новичков. Ну, новички... Машинное обучение... Не, питон для них, эт точно.

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

Лично я их не юзаю, но когда нибудь точно захочу посмотреть %) Я же не говорил что именно они нужны, я про то что новых серьезных либ не особо много. Все в питоне.

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

Бгг, растишку не спрашивали. Ты дописал очередной хелловорд на расте? Сообщество ждёт)

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

Аналог telethon'a есть? Нету.

https://metacpan.org/pod/Protocol::MTProto

Отдельно протокол, отдельно боты.

Зачем заниматься дерганьем если можно взять либу и писать?

Которая дергает ту же с/с++ либу. В перле взаимодействие организовывается просто. Но аргумент принимается. Потому и сказал, для новичков питон безальтернативен.

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

Ну, тут есть несколько моментов, о которых нужно помнить:

1)Популярное «функция» в целом не совсем здорово, ведь изначально оно обозначало отображение значений из одних в другие, т.е. функция всегда возвращает что-то в ответ на вход, с routine пироги другие, т.к. void.

2)Если посмотреть на иерархию классов, то главным батькой будет Callable, т.е. «что угодно, что можно вызвать», не просто метод или там функция. (кстати, забавной деталью является существование Awaitable, который можно руками реализовать, но не суть). Более точным вариантом Callable является Code, т.е. просто код, у которого есть параметры и который можно вызвать (что отнаследовано), а вот Code уже наследуется Block <- блоком кода. У блока нет названия, но есть сигнатура и это та штука, которую реально сделать синтаксически, просто написав в коде {}. А вот далее у нас появляется рутина, которая не означает функцию (далее, почему) - здесь начинает работать return и multi, до этого их ещё не было.

А вот от рутины наследуются: сабрутина (или то, что больше напоминает функцию в других языках), можно сказать «подпрограмма», если пользоваться совсем старым жаргоном, макрос, метод(!) и подметод. Рутина != функция, потому что она является основой для целого ряда других понятий, прям таки надмножеством. Регулярные выражения, кстати, методы, т.е. Regex наследуется от Method.

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

Иногда расценивается, будто «методы это такие функции, прибитые гвоздями к классу», при этом не учитывается, что на неком, мм, плюс-минус фундаментальном уровне это разные сущности.

3)С русской терминологией вообще не очень, на самом деле, особенно учитывая, что есть термины, аналогов которым в других языках нет. «Junctions», «feed operator»(как написал мой знакомый редактор, «О, оператор кормёжки!»), «contextualizer», вот это вот всё. При переводе intro пришлось здорово изворачиваться.

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

Отдельно протокол, отдельно боты.

https://metacpan.org/source/PEVANS/Protocol-MTProto-0.01/lib/Protocol/MTProto...

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

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

Я сам занимался разработкой ботов для телеги, хоть Дурова не люблю, но надо признать что он оч. удобно всё там сделал. Мне даже не приходило в голову какие-либо библиотеки гуглить. Боты были на Mojolicious.

P.S. Отвечать не нужно (:

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

Спасибо за подробное объяснение! Судя по структуре языка, в нем можно здорово переопределять синтаксис. Как же хочется в нем видеть возрождения идей лиспа~

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

Аналог telethon'a есть? Нету.

Ты чудной. Примерный ход разговора:

- На перл нет библиотек
- Ты не прав. Вот ссылка на CPAN.
- Да, но там нет ничего нового.
- Да вот же, раскрой глаза
- Это не уровень "нейросетей и телеграм".
- Вот либа для телеграм бота.
- В ней нет фичи X!

Бестолковый разговор

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

То есть ты серьезно думал что я считаю будто бы у Perl нету библиотек СОВСЕМ? Или что для Perl не делается ничего нового СОВСЕМ? Ну а библиотеки действительно нету, тут даже не в фичах дело, есть просто парсер протокола, это пишется за 2 минуты и ценности не имеет, я просил не это.

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

Как же хочется в нем видеть возрождения идей лиспа

Возможно, тебе доставит это, к сожалению, звук оставляет желать лучшего, но зато легендарный код метациркулярного вычислителя лиспа появляется уже на седьмой минуте. Презентация может не выглядеть прям полностью готовой, я видел, как он готовил слайды за час до выступления, да и учитывая звук сразу пишу tl;dr: будут гигиенические макросы.

Впрочем, уже сейчас можно писать сленги, которые меняют грамматику.

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

Чуть поправлюсь, т.к. может быть реакция «Да этими обещаниями макросов уже много лет кормят» - речь идёт о том, что язык-полигон для исследования идей макросов, 007, «убит», потому что исследование закончено, и теперь наработки будут портироваться в rakudo. Ну и ещё начата разработка отдельного языка Alma уже чисто для умственных экспериментов любителей макросов, не связанный кроме как исторически.

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

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

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

Ну вообще, он хоть и упоротый, но сейчас не прав ты.

«Профессиональная храбрость» - это вполне себе термин, он используется.

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

Ок, а в чем заключается профессиональная храбрость уборщицы?

У нее швабра в руках.

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

Профессиональная храбрость. Есть профессии, которые связаны с ежедневным риском для жизни (спасатели, спецназовцы, пожарные, водолазы, шахтёры и др.). Люди, выбирающие такую работу, безусловно, обладают определёнными психологическими особенностями. Они больше, чем другие, склонны к риску, им доставляют удовольствие острые ощущения, близость опасности и преодоление трудностей. К тому же, поскольку эти люди постоянно находятся в экстремальных условиях, чувство опасности у них со временем притупляется. Опыт, привычка и профессионализм уменьшают страх, вырабатывается хладнокровное отношение к происходящим событиям. Точно так же начинающий водитель всегда боится не справиться с управлением. Его страшат скользкая дорога, плохая видимость, пробки на дороге, незнание маршрута и т. д. Постепенно приобретая опыт, человек начинает водить машину спокойно.

Из чьего-то ЖЖ. Конечно, на истину не претендует. Ну вот какая у программиста храбрость? Поставить апдейт и молиться, чтобы ничего не отвалилось?

Ну хотя ладно, пусть будет у программиста храбрость. У меня просто бомбануло от его диагноза по одному посту.

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

Джункции

Навелосипедил на классах какое-то подобие ваших джункций. Работать будет и на Python 2, и на Python 3.

class junction(object):
    def wrapper(name):
        def generic_method(self, *args, **kwargs):
            return self._wrapattr(name)(*args, **kwargs)
        return generic_method
    for name in (
        '__eq__',
        '__add__',
        '__sub__',
        '__mul__',
        '__truediv__',
        '__div__',
        '__lt__',
        '__gt__',
        ):
        locals()[name] = wrapper(name)
        
    def __init__(self, predicate, items):
        self.predicate = predicate
        self.items = items
        
    def _wrapattr(self, name):
        def inner(*args, **kwargs):
            items = self.items
            for (n, i) in enumerate(items):
                items[n] = getattr(i, name)(*args, **kwargs)
            else:
                if isinstance(items[0], bool):
                    if self.predicate(items):
                        return True
                    else:
                        return False
                else:
                    return self
        return inner

##################
# `any` и `all` есть в Python 3, но написал, чтобы и втором питоне работало.

def any(iterable):
    for i in iterable:
        if i:
            return True
    else:
        return False

def all(iterable):
    for i in iterable:
        if not i:
            return False
    else:
        return True

def one(iterable):
    counter = 0
    for i in iterable:
        if i:
            counter += 1
        if counter > 1:
            return False
    else:
        return True

def none(iterable):
    for i in iterable:
        if i:
            return False
    else:
        return True

##################

j1 = junction(any, [1, 2, 3])
print(3 == j1 + 1)

j2 = junction(all, [1, 2, 3])
print(10 > j2 * 5 - 7)

j3 = junction(one, [4, 6, 8])
print( 0 < j3 / 2 - 3)

j4 = junction(none, ["hello", "world", ""])
print("hello" != j4 )

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

А вот от рутины наследуются: сабрутина (или то, что больше напоминает функцию в других языках), можно сказать «подпрограмма», если пользоваться совсем старым жаргоном, макрос, метод(!) и подметод. Рутина != функция, потому что она является основой для целого ряда других понятий, прям таки надмножеством. Регулярные выражения, кстати, методы, т.е. Regex наследуется от Method.

Похоже на описание ада для злоупотреблявших ООПой.

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

Я просто смайлики не ставлю, то очевидно была несмешная шутейка. Зря бомбишь. А храбрость таки нужна. Одно неверное движение и работа нескольких тысяч встанет. Конечно это не так страшно как не вытащить котика из горящей хрущёвки, но тоже неприятно. И очень часто бывают ситуации, как и в любой профессии наверное, когда ты делаешь то что не обязан, чтоб помочь другим планктонинам. Причём, в случае успеха, лично ты профита не получишь, но если что-то пойдёт не так - нагарит твоя срака.

perl5_guy ★★★★★
()
Ответ на: Джункции от Virtuos86

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

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

    has $.default is required where Callable|Bool|Int|Str;

или там банальное:

    when LDIF::Op::ldif-moddn|LDIF::Op::ldif-modrdn {...}

Всё это можно переписать используя операторы напрямую. И интерполировать (ээ, как можно обозвать катаморфизм нормально... В общем, вычислить оператор на пачке булей) можно метаоператорами.

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

Реализация не совсем полная(да и чёрт с ней, на самом деле)

Конечно, не пользоваться же ей.

но как для велосипеда выглядит интересно

только в этом контексте оно и интересно

После работы попробую портировать

Куда портировать? На перл 6? Хорошая шутка.

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

Куда портировать? На перл 6? Хорошая шутка.

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

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

Значит я ещё помню немного питон!

В Perl 6 операторы это просто сабрутины, которые можно определять как всё остальное, только с указанием «фиксности»(префиксные и прочие постциркумфиксные), например:

sub postfix:<but-cooler>($a) { say "This is $a, but cooler!" }
42 but-cooler;
'Humanity' but-cooler;

# multi чтобы не перекрывать остальные реализации, без него 50 + 42 упадёт
multi sub infix:<+>($a where 42, $b) { $a #`( 42 is so pretty you don't need anything else ) }
say 42 + 50; # 42
say 50 + 42; # 92
say 42 + "WTF"; # 42

Ну и так можно выразить любой оператор с любой фиксностью, указать его precedence по отношению к другим и т.п..

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

Извиняюсь что немного не по теме, но хотелось бы узнать и за что отвечает Routes на 3 строчке. И зачем автор просит его изменить тоже интересно. Хочу узнать так как у меня была проблема с запуском вот этого.

===SORRY!===Could not find Routes at line 3 in:
inst#/home/lil/.perl6    
inst#/home/lil/rakudo/install/share/perl6/site    
inst#/home/lil/rakudo/install/share/perl6/vendor    
inst#/home/lil/rakudo/install/share/perl6    
ap#    
nqp#    
perl5#
Cirno
()
Ответ на: комментарий от Cirno

В третьей строчке импорт файла Oddmuse::Routes, он находится тут.

Когда ты пишешь `perl6 -Ilib service.p6`, то `-Iчто-то` просто добавляет это самое что-то в путь, где искать модули, думая, что это путь от места запуска(ну и можно абсолютный тоже туда, не вопрос). Есть директория `lib` в корне, поэтому она и подключается, а в ней уже директория `Oddmuse` и в ней файл `Routes.pm6` раскрывается из «Oddmuse::Routes».

Сам же файл Routes это необязательно и можно сделать иначе, т.е. это не магия, а просто соглашение. В данном случае он экспортирует сабрутину routes (строка 39), которая потом в service.p6 указывается серверу как application, который будет решать, какой ответ прислать запросу.

Можно routes и не выносить в другой, и можно не использовать route вообще, но это уже когда как надо.

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

Можно просто сделать `cro stub http test ./test` и он сделает простенькую плашку, зайти туда и `cro run .`, ну и постепенно разбираться со структурой, чем брать движок для вики. Хотя, я не знаю контекста, может нужен именно движок для вики. :)

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

И зачем автор просит его изменить тоже интересно

Мельком пролистал ридми, не увидел, где он просит что-либо изменить(есть только «Feel free to change them in service.p6 and .cro.yml, though», но это про переменные хоста и порта), можно ссылку?

p.s. можешь в ирке писать в личку юзеру sena_kun, чтобы здесь не оффтопить.

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

Значит я ещё помню немного питон!

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

Ну и так можно выразить любой оператор с любой фиксностью, указать его precedence по отношению к другим и т.п..

На вид выглядит примерно так, как сделано в Хаскеле.

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

Если не забуду, вечером напишу алгоритм, по которой там всё сделано.

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

На вид выглядит примерно так, как сделано в Хаскеле

Да, в хаскеле круто ещё за счёт того, что там pattern matching красивее выглядит синтаксически. По мощности будет поменьше, чем у Perl 6 (там же вроде нельзя дёргать произвольный код, только деструктурировать?), но всё равно когда ещё много лет назад увидел определения булевых функций как `and True _ = _` или `or False _ = _`, показалось *таким* очевидным и читабельным.

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

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

Хосспаде, да пишите уже код, сколько можно дрочить на синтаксис? Даже если допустить, что кто-то с бодуна решил внедрить перл6, то вся эта барочная херня все равно будет запрещена в продакшне нормальным тимлидом, потому что кодерам нужно кодить, а не разгадывать ребусы.

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

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

Например, для математика:

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

Или для филолога:

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

Или для физика:

(немножко потроллю) начать сомневаться в несуществовании эфира и попробовать что-нибудь этакое на этой почве доказать.

Если немножко сбавить пафос задачи, на примере программиста:

готовность в одиночку отрефакторить код на 100 тысяч строк.

anonymous
()
Ответ на: Джункции от Virtuos86

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

class junction {
    has &.predicate;
    has @.items;

    method new(&predicate, *@items) {
        self.bless(:&predicate, :@items);
    }
}

multi sub infix:<+>(junction $j, $o) { $j.items .= map(* + $o); $j }
multi sub infix:<+>($o, junction $j) { $j + $o }

multi sub infix:<*>(junction $j, $o) { $j.items .= map(* * $o); $j }
multi sub infix:<*>($o, junction $j) { $j * $o }

multi sub infix:<->(junction $j, $o) { $j.items .= map(* - $o); $j }
multi sub infix:<->($o, junction $j) { $j.items .= map($o - *); $j }

multi sub infix:</>(junction $j, $o) { $j.items .= map(* / $o); $j }
multi sub infix:</>($o, junction $j) { $j.items .= map($o / *); $j }

multi sub infix:«>»(junction $j, $o) { so $j.predicate()(|$j.items.map(* > $o)) }
multi sub infix:«>»($o, junction $j) { so $j.predicate()(|$j.items.map($o > *)) }

multi sub infix:«<»(junction $j, $o) { not $j > $o }
multi sub infix:«<»($o, junction $j) { not $j < $o }

multi sub infix:<==>(junction $j, $o) { so $j.predicate()(|$j.items.map(* eq $o)) }
multi sub infix:<==>($j, junction $o) { $o == $j }

multi sub infix:<!=>(junction $j, $o) { not $j == $o }
multi sub infix:<!=>($j, junction $o) { not $o == $j }

my $j1 = junction.new(&any, 1, 2, 3);
say 3 == $j1 + 1;

my $j2 = junction.new(&all, 1, 2, 3);
say 10 > $j2 * 5 - 7;

my $j3 = junction.new(&one, 4, 6, 8);
say 0 < $j3 / 2 - 3;

my $j4 = junction.new(&none, "hello", "world", "");
say "hello" != $j4;


sub any(*@a) { so [||] @a }

sub all(*@a) { so [&&] @a }

sub one(*@a) { so [^^] @a }

sub none(*@a) { not any @a }
Lilly
()
Ответ на: комментарий от Lilly

so $j.predicate()(|$j.items.map(* > $o)) расписывается, конечно, в что-то такое:

my &pred = $j.predicate;
my @items = $j.items.map(* > $o);
&pred(|@items).Bool;

чтобы понятнее было.

$j.items .= map(* + $o); $j расписывается в

$j.items = $j.items.map(-> $el { $el + $o });
return $j;
Lilly
()
Ответ на: комментарий от Lilly

Ага, скорее всего проглядел. Поначалу я реализовывал другую идею, а потом переписал многое, а к тому, что сразу заработало, как надо, и не возвращался толком. Ну и я там местами сделал академично, а не по-какирски, например, использование ветки else цикла for это не самая популярная практика у питонщиков. С другой стороны местами я и нашлепал абы как).

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

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

Если ты про wrapper с generic_method, то это ж элементарщина:
1. Нам надо, чтобы к экземплярам класса junction можно было применять всякие операторы. В питоне эта машинерия устроена как дерганье соответствующих «специальных» методов (вида __%metodname%__). Значит, надо прописать классу эти методы.
2. Я выбрал самый дубовый. В самом теле класса циклом устанавливаю ему «всеядный» псевдометод — функцию, которая принимает любое количество любых аргументов и, соответственно, может успешно имитировать интерфейс и арность любого метода.
_wrapattr остался от предыдущей версии, я об этом писал в пред. комментарии, но пихать его в generic_method показалось совсем плохой идеей: как-то всё перегружено будет выглядеть. Так и оставил.
3. Итого, класс успешно складывается, делится, множится и вычитается, остальное дело техники.

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

Если ты про wrapper с generic_method, то это ж элементарщина:

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

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

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

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

1)По каким критериям сравнивать примеры? По длине? Ну нет. По интуитивности-понятности? Очевидно же, что будет понятней то, с чем больше знаком. По скорости? Отличный метод узнать, что бенчмарки плохо экстраполируются на реальность. Как тогда?

2)Любой нетривиальный код можно максимально тривиализировать либо наоборот, обфусцировать, что будет зависеть от настроения и чувства садизма того, кто пишет, что делает сравнение не совсем прямым. Если же пишется максимальная схожесть, то идиоматичность языка исчезает, потому что из-за разного подхода то, что можно написать на X можно написать на Y, но не всегда можно наоборот из-за ограниченности.

Ну я помню, мне показали код на go, который рекурсивно считает факториалы, раскидывая каждый в отдельный поток, код на го:

(кстати, cast vertexua, думаю, будет интересно)

func main() {
    jobs := make(chan int, 100)
    results := make(chan int, 100)

    go worker (jobs, results)
    go worker (jobs, results)
    go worker (jobs, results)
    go worker (jobs, results)

    for i := 0; i < 100; i++ {
        jobs <- i
    }
    close(jobs) // можно ли забыть сделать вот это?

    for j := 0; j < 100; j++ {
        fmt.Println(<- results)
    }
    // где close(results)?
}

func worker(jobs <-chan int, results chan<- int) { // если перепутаешь стрелку?
    for n := range jobs {
        results <- fib(n)
    }
}

func fib(n int) int {
    if n <= 1 {
        return n
    }
    return fib(n - 1) * fib(n - 2)
}

Вот сделанная в очень похожем стиле версия на Perl 6:

sub MAIN() {
    my $jobs = Channel.new;
    my $results = Channel.new;

    for ^4 {
        start worker($jobs, $results);
    }

    $jobs.send($_) for ^100;
    $jobs.close;

    react whenever $results.Supply -> $result {
        say $result;
    }
}

sub worker($jobs, $results) {
    react whenever $jobs.Supply -> $job {
        $results.send: fib($job);
        LAST { $results.close }
    }
}

sub fib($n) {
    return 1 if $n <= 1;
    return fib($n - 1) + fib($n - 2);
}

Есть канал с работой, есть канал с результатами, есть N воркеров, которые ждут работу и считают.

Вот плюс-минус идиоматический Perl 6 для этой задачи:

sub fib($n) {
    return 1 if $n <= 1;
    return fib($n - 1) + fib($n - 2);
}

# Числа от нуля до 100...
my @jobs = 0..100;
# Вызываем map, который для для каждого числа из последовательности вызывает fib.
# Вызов race создаёт и управляет пулом воркеров:
# параметр degree позволяет задавать, сколько будет воркеров
# без него рантайм сам определит, сколько воркеров оптимально для этой задачи
# batch задаёт, сколько элементов мы хотим отдавать одному воркеру за раз, тоже опциональный
my $results = @jobs.race(batch => 1, degree => 4).map({ fib($_) });

# делаем из последовательности результирующих значений
# Supply, который позволяет нам асинхронно стримить
# значения, каждое печатаем до тех пор, пока
# пока они не закончатся
react whenever $results.Supply -> $result {
    $result.say;
}

Убери оттуда комментарии и получится меньше десяти строчек на всё про всё. При этом код, на мой взгляд, проще читать: «Результаты это когда мы берём всю работу и её выполняем параллельно, по одной штуке в пачке, за четыре потока». Потом ты говоришь «Отреагируй, whenever есть асинхронный результат, напечатай его. Когда $results будет автоматически закрыт (не нужно бояться за забытый close), автоматически закроется и whenever-подписка и react блок закончится. Что самое забавное, первый код мне назвали „более элегантным“, чем по сути декларативное решение. И как в таких условиях сравнивать примеры одного и того же алгоритма там и там?

(дисклеймер: да, в go поддержка горутин более вылизана за все годы, но подкапотную реализацию всегда можно улучшить, а вот стандартные паттерны написания когда остаются такими навеки, их уже не пропатчишь, не ломая совместимость)

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

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

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