LINUX.ORG.RU

Racket 6.7

 ,


1

4

Состоялся выпуск Racket 6.7 — языка программирования общего назначения из семейства Lisp/Scheme.

Основные изменения:

  • С Racket теперь можно собрать графическое приложение для Android с помощью проекта racket-android.
  • В REPL стало доступно редактирование, история и мета-команды (такие как ,load или ,describe).
  • Пакетная система теперь поддерживает аутентификацию при установке пакетов из git.
  • Компилятор байткода получил дополнительные оптимизации в операциях со списками, строками и байтовыми строками.

>>> Страница проекта

>>> Подробности

★★★★

Проверено: Shaman007 ()

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

Rust работает с обычными тредами, не с легковесными.

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

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

Rust не страхует от дедлоков.

Он не заставляет писать так, что они могут возникнуть на каждый чих. То же самое можно было сказать в сравнении C++ vs Erlang.

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

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

М-м, что имеется в виду? Не распарсил.

Haskell компилируемый, например. В его основной реализации, GHC, на уровне рантайма есть как потоки, привязываемые к системным, так и потоки зеленые.

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

Ну хаскель рантайм имеет определенную схожесть с интерпритатором. Я кстати ожидал этот аргумент.

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

ручное порционирование задач на блоки

Вот с этим основное неудобство.

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

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

В win3.11 такое было и для Паскаля и для Си.

Каждые n инструкций и как минимум раз внутри любого цикла вызывался yield, который передавал управление на следующий «поток». Этот yield вставлялся компилятором.

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

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

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

вобщем лучше руками yield ставить там где они нужны

Гм... Возьми какую-нибудь программу на ~1000 строк и попробуй расставить yield так, чтобы между ними гарантированно было не больше 1мс. Очень быстро либо сведёшь к yield после каждой строчки, что хуже, чем расстановка автоматом, или нарушишь требования по времени.

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

Только он же сбрасывает кеш проца

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

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

При проверке необходимости

эмм а как понять надо ли мне переключать или нет?

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

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

эмм а как понять надо ли мне переключать или нет

Псевдокод:

for t in threads do
  t.wait -= tick;
  if (t.wait <= 0) jmpToSchedule(t);

Этот кусок инлайнится. Соответственно, если переключения не произошло, то срыва кэша тоже не произошло.

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

Сможешь вручную разбить программу на куски, каждый из которых гарантированно выполняется не больше 1/10 секунды, при произвольных входных данных?

Впрочем, зачастую хватает просто сделать асинхронный ввод-вывод.

Опять epoll/select. Без зелёных тредов где-то на этом пользовательская асинхронность и заканчивается.

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

Так и не понял, чем тебе не угодил хаскелевсий рантайм GHC. И причем здесь интерпретатор, вообще?

Этот рантайм, кстати, довольно навороченный и

(а) из-за разделения потоков на обычные (они же, зеленые) и потоки, привязанные к системным (для работы, например, с GUI), и

(б) из-за поддержки транзакционной памяти (в STM мы должны отлавливать автоматически момент, когда меняется состояние переменой для повторной попытки провести атомарные операции), и

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

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

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

рантайм хаскелевского GHC

Где-то можно почитать как он устроен?

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

Начнем с того, что там вообще некая Spineless Tagless G-machine, которая реализует лень. Одного только этого достаточно, чтобы механизм выполнения стал минимум нетипичным для C-ориентированного процессора. В принципе можно попробовать сделать хардварную хаскель-машину, но почему-то бытует мнение, что хардварные реализации ЯП хуже, чем софтварные, чему я так и не поверил. Железо общего назначения обязано же быть хуже специализированного в его же области применения (это, блин, очевидно).

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

Да, наверняка можно в статьях и исходниках, но в прикладном плане на мой взгляд интереснее книга «Parallel and Concurrent Programming in Haskell» от автора, который реализовал этот самый рантайм

dave ★★★★★ ()

Кто расскажет: ядро системы и основные библиотеки переписывают на «типизированном наречии», или оно так и остается для «хипстеров»?

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

Кто расскажет: ядро системы и основные библиотеки переписывают на «типизированном наречии»

Так давно уже. typed/racket/base и typed/racket работают.

или оно так и остается для «хипстеров»?

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

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

Так давно уже. typed/racket/base и typed/racket работают.

Здорово! И есть бенчмарки бестиповых/типизированных тестов?

И бестиповым тоже останется.

Так это таки два совершенно разных «ядра», или бестиповое - детипизированная прокладка над типизированным? Хуже, если наоборот.

yyk ★★★★★ ()

Это для тех, кому Лиспа не хватает?

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

Здорово! И есть бенчмарки бестиповых/типизированных тестов?

Типизированный равен бестиповому без проверок. То есть везде заменяемь car на unsafe-car и так далее. Получится идентичный байткод.

Преимущество типизированного в статических проверках. Типы проверяются при компиляции, а не при запуске.

или бестиповое - детипизированная прокладка над типизированным? Хуже, если наоборот.

Совсем внизу си, чуть выше нетипизированный racket, к нему указаны типы.

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

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

Но если

Совсем внизу си, чуть выше нетипизированный racket

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

Я надеялся, что уже весь нетипизированный код - это откастованный на Any типизированный код, а там по прежнему всё наоборот.

Спасибо за разъяснения.

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

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

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

(define (map2 f l1 l2)
  (if (and (procedure? f)
           (procedure-arity-includes? f 2)
           (list? l1)
           (list? l2)
           (= (length l1) (length l2)))
      (let loop ([l1 l1][l2 l2])
         (cond
           [(null? l1) null]
           [else (cons (f (car l1) (car l2)) 
                       (loop (cdr l1) (cdr l2)))]))
      (map f l1 l2))
в цикле loop оптимизирует car и cdr, так как есть проверка на list?. А если этот код (как в стандартной библиотеке) помещён внутрь begin-encourage-inline, то при вызове из typed вызовы list? тоже будут выкинуты.

В сишных вообще проверки только контрактные, а в typed они выкидываются. Остаются только функции типа find-seconds из racket/date, но они крайне редко являются узким местом.

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

Я надеялся, что уже весь нетипизированный код - это откастованный на Any типизированный код

В случае Racket получается хуже. При вызове типизированного кода из нетипизированного автоматически создаётся контракт на типах. Но возможности контрактов гораздо шире, чем возможности типов. Например, на контрактах я могу потребовать произвольное число списков равной длины (например, для map), а на типах не смогу. С другой стороны, тип для map

(All (c a b ...)
      (case->
       (-> (-> a c) (Pairof a (Listof a)) (Pairof c (Listof c)))
       (-> (-> a b ... b c) (Listof a) (Listof b) ... b (Listof c))))
приведёт к тому, что результат должен проверяться на ограничение на тип элементов.

откастованный на Any типизированный код

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

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

В случае Racket получается хуже. При вызове типизированного кода из нетипизированного автоматически создаётся контракт на типах.

Сурово. Тогда сложно интегрироваться. Неминуемо теряешь в скорости.

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

Неминуемо теряешь в скорости.

На самом деле не сильно. Также как на проверке любых контрактов. Теоретически можно сделать версию Racket, в которой модно было бы отключать проверки (как в (speed 3) (safety 0) в Common Lisp), но разработчик не хочет. Так как такой код глупо выставлять в продакшен (любая мелкая ошибка обвалит всё), и он бессмысленен при отладке. По сути только для бенчмарков.

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

Эхх написать бы гибридный ЯП, который умеет компилировать куски кода, в которых достаточно типовой информации в Си-подобный машинный код, но при этом оставляет возможность писать динамически на уровне руби. В итоге когда весь проект обвешается типами, он догонит Си по скорости. Был бы стимул применять прототипирование, а то как-то не интересно разбираться с ЯП, прототип на котором потом всеравно пойдет в топку из-за наличия тормозящего GC например.

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

И что на нем можно писать числомолотилки и гонять родные массивы в си поинтеры без переформатирования данных?

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

В современных динамических языках типа Common Lisp при покидании числом пределов функции приходится добавлять тег для определения того, что объект является числом, а это обычно ведет к боксингу (у этого явления разные названия в разных языках). Из-за этого числодробилку сильно вряд ли получится написать на таком языке.

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

В общем, в Common Lisp, пожалуй, тут набили все возможные шишки, которые можно себе представить на этом пути)

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

Ну так блин, указываешь что у тебя массив типа [int] и гарантированно получаешь struct { size_t size; int* data; } в реализации. Разве нельзя так сделать ну хоть гденибуть?

PS: я спрашивал не про сабж. Речь шла о Dylan.

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

Ну так блин, указываешь что у тебя массив типа [int] и гарантированно получаешь struct { size_t size; int* data; } в реализации. Разве нельзя так сделать ну хоть гденибуть?

В SBCL так работает.

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

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

Это Common Lisp.

В итоге когда весь проект обвешается типами, он догонит Си по скорости.

Можешь глянуть на Java и Haskell. Типами обвешаны по уши, но Си им никогда не догнать. Потому что сборщик мусора. А в случае Common Lisp всё ещё чуть-чуть хуже, так как при

(defun f (x)
  (declare (type fixnum x))
  (+ x 1))

(defun g (x)
  (if (fixnump x) (f x) (format nil "~a" x)))
в функции f при любом раскладе придётся делать преобразование lisp-object->fixnum. Также + обязан корректно обрабатывать переполнение. И функция g должна корректно работать, если функция f изменилась после начала работы программы (а значит вызов функции не по ссылке, а по символу).

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

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

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

Это фактически запрещает в a+b заменять явный вызов a.plus(b) на ассемблерный вызов, так как никто не гарантирует, что в момент выполнения plus() всё ещё будет производить сложение, а не делать что-нибудь ещё.

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

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

Кстати, на Racket можно. Только арифметику надо использовать из http://docs.racket-lang.org/reference/unsafe.html и массивы из http://docs.racket-lang.org/foreign/homogeneous-vectors.html

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

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

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

Кстати говоря подобный подход применяется в хаскеле ну и в смолтолке можно перекомпилировать метод с разной оптимизацией. Да и вообще jit об этом. Надо только довести технологию до ума, чтоб даже GC выпиливало с рантайма, если ни одного циклического графа в проге не должно появиться.

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

можно добавлять методы в любой момент.

Добавлять в рантайме можно только если 1) есть код добавления 2) есть некая вариация eval. Если ни того ни другого нету, то значит можно смело оптимизить. Кроме того evalы можно ограничивать песочницами, собственно сабж как раз демонстрирует техники оптимизации динамической системы при некоторых ограничениях на evalы и мутабельность на уровне модуля.

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

Добавлять в рантайме можно только если 1) есть код добавления 2) есть некая вариация eval.

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

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

Когда компилишь екзешку можно просто проверить все ветки кода.

По-моему получится проблема останова в профиль. Не?

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

используется в стандартной библиотеке.

Ну так там же можно аналитически ограничить область влияния + многое вынести в компилтайм по причине независимости от ввода узера (в условиях сборки конкретной екзешки хотя бы).

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

Racket быстрее чем Chez http://www.larcenists.org/benchmarksGenuineR6Linux.html

По ссылке сравнение с бесплатным интерпретатором. Компилятор chez на тот момент был закрытым и платным и в сравнении не учавствовал. И считался самым быстрым. Сам не бенчил, не знаю текущую ситуацию.

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

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

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

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