LINUX.ORG.RU

Вышел Racket 6.3

 , ,


2

9

Доступен для скачивания релиз 6.3 языка программирования Racket — http://racket-lang.org/.

Новшества:

  • При раскрытии макросов используется новое представление связывания, что позволяет проще понимать как макросы сохраняют связывания, особенно при вовлечении в процесс раскрытия нескольких модулей и при отклонении от гигиены при раскрытии.
  • GUI-библиотека Racket теперь использует Gtk3+ по умолчанию.
  • Новое руководство по Redex.
  • Улучшена проверка синтаксических ошибок для Redex-паттернов.
  • Bluebox стали более агрессивными в плане отыскания имён для поиска в документации.
  • Подмодули теперь полностью поддерживаются в Typed Racket.
  • Библиотека typed/racket/unsafe предоставляет формы импорта/экспорта для обхода генерации контрактов.
  • Typed Racket предоставляет экспериментальную поддержку units (из racket/unit).
  • Экспериментальная форма define-new-subtype позволяет указывать тонкие различия, без которых типы считаются идентичными (аналог new type в Haskell).
  • Конструктор типов Promise изменился, нарушив обратную совместимость для устранения promise, созданных с помощью promise/name.
  • Пакеты unstable-* исключены из главного дистрибутива.
  • big-bang поддерживает режим display-mode, что позволяет т.н. «мировым» программам (интерактивным, графическим программам, состоящих из простых математических функций) занимать весь экран целиком.

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

anonymous

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

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

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

Разве? А если внутри функции что-то типа:

if ...
    return носорог
else 
    return обезьяна
То мы не увидим ошибку только если попадём в нужную ветку?

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

А больше и не надо

Для пионерских поделок - да.

Нет, не вернет. Если ф-я ожидает 2, а мы всунем «2» - то сразу убедимся в наличии ошибки.

Нет, если не проверять и тип:

print(2 == "2");
echo 2 == "2";

Или значение само определяет как его сравнивать:

class Test:
    def __eq__(self, other): 
        return True

print 2 == Test()

Что за бред ты несешь?

Больше читай и учись, тогда поймешь.

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

Для пионерских поделок - да.

Да нет, для любых поделок.

Нет, если не проверять и тип:

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

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

Зачем же ты приводишь в пример язычок со слабой типизацией?

Я привел в пример три разных языка. И по сути самых популярных с динамической типизацией - JS/PHP/Python.

Давай возьмем сильную динамическую.

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

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

А зачем писать такие функции?

А зачем вообще делают ошибки? Вот не делали бы и все было бы хорошо.

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

А зачем вообще делают ошибки?

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

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

Я привел в пример три разных языка. И по сути самых популярных с динамической типизацией - JS/PHP/Python.

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

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

Конкретнее можно? Без выдумок и некорректных аналогий.

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

Если ты говоришь о трех конкретных языках тогда и не надо говорить про типизацию
Конкретнее можно?

Тебе просто поспорить хочется? Без примеров тебе не понятно, с ними ты начинаешь ворочать носом, что они почему-то показаны на конкретных языках.

Без выдумок и некорректных аналогий.

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

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

А зачем писать такие функции?

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

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

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

Да, но одним тестом тут уже не отделаешься.

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

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

«Ошибка» - это нечто случайное. Написать же ф-ю, которая возвращает то жирафов то носорогов случайно нельзя, только намеренно. Вот я и спрашиваю - зачем?

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

Это же твоя

Нет, не моя.

Тебе просто поспорить хочется? Без примеров тебе не понятно, с ними ты начинаешь ворочать носом, что они почему-то показаны на конкретных языках.

Ты привел пример недостатков _слабой_ типизации. Да, слабая типизация имеет недостатки (не важно при этом статическая она или динамическая), с этим никто не спорит. Динамическая же типизация недостатков не имеет.

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

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

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

Это ещё почему нельзя? А если функция вызывает другие функции, которые в свою очередь, тоже что-то вызывают? Вполне возможно ошибиться.

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

Это ещё почему нельзя?

А как? Я не вижу способа.

А если функция вызывает другие функции

Ну то есть какая-то другая функция возвращает и жирофов и носорогов, значит так намеренно написана. Возвращаемся к вопросу - зачем?

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

Возвращаемся к вопросу - зачем?

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

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

Написать же ф-ю, которая возвращает то жирафов то носорогов случайно нельзя, только намеренно. Вот я и спрашиваю - зачем?

http://clhs.lisp.se/Body/f_file_w.htm : возвращает время или nil. Это два разных типа.

Ещё бывает функции типа get-xml-content, которая может вернуть строку, может объект подузла, может число, может дату, может ещё что-нибудь...

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

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

Прежде чем использовать ф-ю - надо знать как она работает. Логично, нет?

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

И в отличие от проверок компилятора, они не дают никаких гарантий.

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

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

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

надо знать как она работает. Логично, нет

Многие говнокодеры забивают на обработку ошибок. А сделать тест, который провоцирует ошибку, особенно если тестирование по принципу «чёрного ящика» задача нетривиальная.

Например, для get-xml-content надо для теста сформировать файл, который содержит тип, не учтённый в программе. Если тесты пишет сам разработчик, то это вообще нереально (если бы он про этот тип вспомнил, он бы и в программе про него вспомнил).

К слову, статически типизированные языки от такого не спасают. В Haskell возможны функции типа «f x | x > 0 = x + 1». У неё тип параметра Num, но для отрицательных чисел она падает.

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

Прежде чем использовать ф-ю - надо знать как она работает. Логично, нет?

Да. Но мы говорим о реальной ситуации или об идеальном мире? В реальности люди не всегда документацию читают плюс она не обязательно присутствует. Тем более, что «знать как она работает» - это уже попахивает изучением исходников самой функции плюс всех функций, что она вызывает. И статическая типизация тут сработает как надо: не получится случайно вернуть тип «животное» или «носорог | обезьяна» из функции, которая возвращает носорога.

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

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

Да. Но мы говорим о реальной ситуации или об идеальном мире?

Если ты используешь ф-ю, спецификация которой тебе неизвестна (да, «знать как работает» - наверное, не очень удачное выражение), то никакие типы уже не спасут, извини.

Понятно дело, что это только один класс ошибок из целой кучи возможных

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

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

Если ты используешь ф-ю, спецификация которой тебе неизвестна (да, «знать как работает» - наверное, не очень удачное выражение), то никакие типы уже не спасут, извини.

Именно в этом случае - спасут. Но зачем на личности переходить? Использую я или нет - это дело десятое. Ты прямо скажи - неужели ситуация действительно невероятная?

Но она требует затрат.

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

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

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

А можно я?

1. При статической типизации необходимо указывать типы => больше писать. Хотя при нормальном документировании этот пункт несущественен (в документации в динамическом языке всё равно придётся указывать типы)

2. Достаточно большое количество кода не выражаются в статической типизации. Например, в Haskell нельзя написать функцию, которая могла бы работать с произвольными цепочками объектов с типом «Cons a b». Хотя в Typed Racket эта проблема практически решена.

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

Именно в этом случае - спасут.

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

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

Затраты на разработку и поддержку, конечно же. Написание лишнего кода, его усложнение, борьба с тайпчекером. Кроме того статическая типизация дает мнимые гарантии корректности - ты видишь тип и полагаешь, что ф-я его не нарушает, хотя легко может нарушать из-за кастов, это может быть причиной целого класса ошибок, от которого динамика избавлена by design. Кроме того, динамика изначально прививает программисту дисциплину, количество статического говнокода на порядок больше чем в динамике.

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

1. При статической типизации необходимо указывать типы => больше писать.

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

2. Достаточно большое количество кода не выражаются в статической типизации.

Учитывая, что ты сам говоришь про то, что проблема «практически решена», значит это проблема не статической типизации в целом, а отдельных реализаций. Так?

Плюс есть некоторые сомнения относительно того действительно ли это «достаточно большое» количество кода.

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

Если результат работы ф-и неизвестен

Результат (возвращаемое значение) как раз будет известен. «Побочные эффекты» - нет.

Но ты не ответил на мой вопрос - неужели считаешь, что ситуации когда один человек дал функции не самое подходящее имя и забил на документацию, второй выбрал функцию по имени («получить-носорга»), использовал, запустил разок - заработало и на этом успокоился, в реальном мире не встречаются?

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

Ну да, вместо этого «by design» будет другой класс ошибок. Но не важно, лучше расскажи как касты ломают типы. Ты про аналоги reinterpret_cast когда что угодно куда угодно скастовать можно? Можно подумать в динамике я не могу в объект мусор записать. В крайнем случае, через FFI.

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

Ну-ну. Статистика есть?

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

Напиши для питона тип функции reduce.

Для раста будет как-то так:

fn reduce<T, I, F: Fn(T) -> T>(i: I, f: F) 
    where I: Iterator<Item = T> {
}

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

отлично. еще бы отступы эти убрать дуракцие и будет приличный язычок

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

В хаскеле ведь есть вывод типов «везде», так что можно не писать больше.

Он местами загадочно себя ведёт.

import Control.Monad
import qualified Data.HashTable.IO as H
import System.Environment

main = do
  [size] <- map read `fmap` getArgs
  m <- H.new
  forM_ [1..size] $ \n -> H.insert m (n :: Int) n
  v <- H.lookup m 100
  print v

Даёт:

test.hs:7:8:
    No instance for (Data.HashTable.Class.HashTable h0)
      arising from a use of ‘H.new’
    In a stmt of a 'do' block: m <- H.new
    In the expression:
      do { [size] <- map read `fmap` getArgs;
           m <- H.new;
           forM_ [1 .. size] $ \ n -> H.insert m (n :: Int) n;
           v <- H.lookup m 100;
           .... }
    In an equation for ‘main’:
        main
          = do { [size] <- map read `fmap` getArgs;
                 m <- H.new;
                 forM_ [1 .. size] $ \ n -> H.insert m (n :: Int) n;
                 .... }

Приходится писать:

import Control.Monad
import qualified Data.HashTable.IO as H
import System.Environment

main = do
  [size] <- map read `fmap` getArgs
  m <- H.new  :: IO (H.BasicHashTable Int Int)
  forM_ [1..size] $ \n -> H.insert m (n :: Int) n
  v <- H.lookup m 100
  print v

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

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

В типизированном случае будет вместо обезьяны бросать исключение. С точки зрения надёжности почти идентичные ситуации.

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

Ну-ну. Статистика есть?

Статистика очень простая - без дисциплины на динамике программу больше 100 строчек не напишешь.

Ты про аналоги reinterpret_cast когда что угодно куда угодно скастовать можно? Можно подумать в динамике я не могу в объект мусор записать.

В динамике у тебя нету мнимых гарантий того, что это не произойдет.

Результат (возвращаемое значение) как раз будет известен. «Побочные эффекты» - нет.

Откуда он будет известен, если ты не знаешь, что делает ф-я? Например у тебя ф-я yoba и ты применяешь ее к списку, надеясь, что она его отсортирует. С какой стати?

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

Статистика очень простая - без дисциплины на динамике программу больше 100 строчек не напишешь.

Наличие PHP и JS, и их популярность у говнокодеров, очевидно опровергают это высосанное из пальца утверждение.

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

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

Совсем не обязательно. Разные типы возвращаемого значения будут явно видны. Исключение - не возвращаемое значение.

С точки зрения надёжности почти идентичные ситуации.

Ну да, наверное. Хотя тут, опять же, от языка зависит. Есть же в джаве «checked exception», в расте попытались «отказаться от исключений», в хаскеле я не силён, но тоже, вроде, разные варианты есть.

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

Статистика очень простая - без дисциплины на динамике программу больше 100 строчек не напишешь.

Это не статистика, а убеждение. Могу встречное выдвинуть: в динамике ошибок в среднем больше. Но ты ведь не согласишься.

В динамике у тебя нету мнимых гарантий того, что это не произойдет.

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

Опять же, разговор о гарантиях тут - это передёргивание. Потому что в объект мусор не пишут в 99% случаях (особенно если взять что-то более высокоуровневое чем С/С++), а вот не тот тип в динамике очень даже может оказаться. Вероятности совсем разного порядка. Хотя мне кажется, что ты и тут не согласишься.

Например у тебя ф-я yoba и ты применяешь ее к списку, надеясь, что она его отсортирует. С какой стати?

Это опять увод разговора в сторону. Давай другой пример: есть у меня функция sort, причём для типизированного языка я ещё и увижу что она принимает и что возвращает. Это несколько больше информации, чем просто «yoba» не находишь?

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

Это опять увод разговора в сторону. Давай другой пример: есть у меня функция sort, причём для типизированного языка я ещё и увижу что она принимает и что возвращает.

Получишь что-то вроде такого.

> sort
- : (All (a b)
      (case->
       (-> (Listof a)
           (-> a a Boolean)
           [#:cache-keys? Boolean]
           [#:key (-> a a)]
           (Listof a))
       (-> (Listof a)
           (-> b b Boolean)
           [#:cache-keys? Boolean]
           [#:key (-> a b)]
           (Listof a))))

Сильно легче?

А для нетипизированного будет описание

sort sequence predicate &key key => sorted-sequence

Arguments and Values:

sequence - a proper sequence. 

predicate - a designator for a function of two arguments that returns a generalized boolean. 

key - a designator for a function of one argument, or nil. 

sorted-sequence - a sequence. 

Обрати внимание на слово «designator». С точки зрения типа это «функция или символ». Но я не знаю ни одной системы типов, в которой можно бы было указать, что тип параметра — символ, совпадающий с именем глобальной функции определённого типа.

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

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

в хаскеле я не силён, но тоже, вроде, разные варианты есть.

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

С точки зрения типа, error x возвращает то же самое, что и функция f x = f x.

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

в расте

Вот, кстати, замечательный пример, где типы ограничивают реализацию: https://github.com/contain-rs/linked-list/blob/master/src/lib.rs

Начиная с

struct Node<T> { 
    prev: Raw<T>, 
    next: Link<T>, 
    elem: T, 
} 

type Link<T> = Option<Box<Node<T>>>; 
 
struct Raw<T> { 
    ptr: *mut Node<T>, 
} 

pub struct LinkedList<T> { 
     len: usize, 
     head: Link<T>, 
     tail: Raw<T>, 
} 

Что приводит к несимметричному коду:

self.tail = Raw::some(&mut *node)
self.head = Some(node)

То есть вместо тривиального алгоритма приходится в голове держать эти преобразования

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

Прежде чем использовать ф-ю - надо знать как она работает.

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

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

Любая математическая либа это набор математических функций

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

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

Сильно легче?

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

А для нетипизированного будет описание

Это подмена понятий. Описание может как присутствовать так и отсутствовать независимо от вида типизации.

И почему ты привёл описание не из (обычного, не типизированного) ракета?

символ, совпадающий с именем глобальной функции определённого типа.

Объясни, пожалуйста, для далёких от лиспа людей, какие именно возможности это даёт.

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

Честно говоря, пример меня совсем не убедил. Особенно про сильное сужение.

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

В хаскеле как раз исключение может быть возвращена из любой функции.

Да, но ведь там несколько способов «работы с ошибками».

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