LINUX.ORG.RU

Racket 8.0

 , ,

Racket 8.0

0

5

Вышла новая мажорная версия языка программирования Racket, основанного на Scheme и нацеленного на создание пользователем собственных DSL.

  • Завершён переход на среду исполнения Chez Scheme — таким образом удалось уменьшить объём генерируемого кода на величину от 10 до 30%, а также значительно ускорить выполнение программ и повысить эффективность.
  • Переписан движок среды тестирования программ.

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

★★★★

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

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

Ты получаешь неопределенное поведение при попытке использовать это самое «определенное значение».

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

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

(не)пределенное поведение

какое отношение оно имеет к семантике

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

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

Поведение как раз имеет отношение семантике.

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

Ты не можешь определиться, что такое значение и тип,

Да нет, это ты не понимаешь, в чем отличие литералов и переменных, и чем число отличается от его представления.

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

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

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

литералов и переменных

Применительно к Си.

«Литерал» - это вообще lvalue выражение, у которой можно взять адрес, при особом желании можно даже присвоить значение (скорее всего с неопределенным поведением). Примеры https://en.cppreference.com/w/c/language/string_literal , https://en.cppreference.com/w/c/language/compound_literal . Чем это отличается от переменной?

Есть еще «константы» - это rvalue выражения. Это всякие целочисленные, символьные, плавающе-точечные константы и тп.

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

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

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

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

Потом главное не забыть, что getAccount надо сравнивать с Fail42, а getBalance c Fail143.

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

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

Будет очевидно, что что-то не так. Но потом надо будет всё равно вспоминать (или идти к определению и смотреть) какой номер у нужного Fail.

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

c == d возвращает истину.

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

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

Да, с учётом наличия operator==(), согласен.

Но остаётся аргумент с switch/case.

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

привет. ты там в треде про Столярова спрашивал, где взять Оберон под MacOS ARM.

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

  1. портировать блекбокс – это один вариант, там в линукс и прочих сам блекбокс сделан как запускалка ELF подсистем из .so, то есть в макоси это будут соответственно mach-o и dylib. и соответственно посмотри в исходниках блекбокса под линукс или под хайку про линкер – DevLinker или как-то так. сам блекбокс.еxe это загрузчик модулей .odc своим особенным StdLoader, для генерации этого .exe используется DevLinker, который генерит PE exe напрямую битхаками и какой-то магией. в этот exe влинкован Kernel, System, StdLoader и управление памятью, сборщик мусора. опционально, компилятор, редактор и всё остальное. интерфейсы с ос реализованы через Host модули. при портировании на линуксы соответственно оно должно генерить ELF а не PE, там особо не заморачивались и сделали враппер, который загружает всё остальное из .so. соответственно, вот это всё под mach-o вместо ELF или PE exe, .dylib вместо .so – и надо портировать.

в общем, посмотри в https://blackboxframework.org/unstable/master/ там где сборки скачать можно как устроено ихнее CI например которое генерирует автоматически -changelog и -buildlog , например такой: blackbox-1.7.3-a1.1133-buildlog это сборки c blackboxframework.org, может более актуальные есть на blackbox.oberon.org, там есть ссылка на github

отсюда видно, как собираются подсистемы и генерируется конечный Blackbox.exe для PE или там ELF через скрипты, которые внутри блекбокса запускает bbscript. zip версия это под венду, портированная под линукс собирается немного по-другому, но принцип тот же. см. скрипты на гитхаб.

  1. второй вариант – использовать A2. который бывший BlueBottle.

сборки бинарные A2 брать здесь gh_yarrom_a2_builds – смотри DarwinA2 64 Installer.dmg , у него же рядом есть привязки под opengl opengloberon

den73 собрал свой форк А2, ЯОС под Zybo (FPGA+ARM) инструкции , для чего вернул взад в свой форк ARM коммит

компилятор Fox оберона из A2 в основной ветке поддерживает ARM.

там же есть ссылка на основную ветку – цюрихский репозиторий https://svn-dept.inf.ethz.ch/svn/lecturers/a2/trunk

anonymous
()
Ответ на: комментарий от anonymous
  1. третий вариант – использовать что-то отсюда:

http://pascal.hansotten.com/niklaus-wirth/project-oberon/

ALO ARM Linux Oberon (Oberon in LNO family, for ARM CPU eg Raspberry Pi)

рядом там лежат, кстати, компиляторы изначального паскаля Вирта

http://pascal.hansotten.com/niklaus-wirth/px-compilers/

и исторические Pascal-M , UCSD p-pascal http://pascal.hansotten.com/ucsd-p-system/ucsd-compiler-and-p-system/

ещё есть совсем простенький учебный PL/0

http://pascal.hansotten.com/niklaus-wirth/pl0/

(после такого вот компилятора недопаскаля на одну страницу кода, честно говоря, забавно было читать всю эту простыню ликсуси в треде по Столярова про то, что мертвый язык, лежит мёртвым грузом, изучать зело сложно и прельстиво не нужно. ну да, ну да. вот что, правда что ли школотроны современныя вот такое минималистичное осилить не могут??? PL/0 -> P4 , даже книжкою. где-то ещё P5 есть. стандартный исо паскаль и pascaline тоже кстати несложны судя по pascalfaq

  1. Herschel herschel.oberon.org вконтактег

в контексте треда конечно – генерацию p-code под UCSD нужно делать на Racket :)))

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

DarwinA2 64 Installer.dmg

ЕМНИП это не полноценный ещё A2 под A1, а скорее A2 под x86 ??? :)

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

кстати, вот там в том треде вылез mumpster, внезапно, не с MUMPS-ами, а почему-то с фортом.

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

Минимальный Forth с нуля jonesforth jonesforth-1 jonesfoth-2 paf

Literate Forth programming – автоматизировать ту же сборку и линковку вместо рюшечек и няшного IDE с какой-то сраной магией внутри

к примеру, существует метакомпилятор форта lbForth

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

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

там классные примеры – формульный калькулятор и собственно асм. где-то там было про Рунге-Кутта вычислительное ядро. вспоминается Дьяконов, что-ли. книжечка издательства Мир. там этой рунгекуты было всего строчек 8 что-ли. полного лайннойза. можно было медитировать (в смысле, meditate) до полного просветления, над каждой буквой :))

вот кстати, пример как мыслит инженер и как программист: инженер пишет какую-то магию которая внезапно работает, а программист строит формульный калькулятор и башню DSLей поверх

ну или взять какой-нибудь Win64FasmForth, но там винда прибита к SPF и FASM.

Gforth на си – существует. под него есть gforth-sdl-opengl , ну где же, где же новый метапрог ? :)))

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

ещё до кучи:

Jack W. Crenshaw «Let’s Build a Compiler»

here

Crenshaw написал простой компилятор паскаля с кодогенератором под x86 (ЕМНИП, на паскале).

затем он был переписан на форте. получилось даже проще и понятнее. весь сорец.

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

ещё был COMFY от Henry Baker. он там реализовал ассемблер 6502 на elisp, ЕМНИП. в пару экранов кода.

потом аналогичное – развернули в полноценный ассемблер x86 под схему. исходники где-то на gnu.savahhan. название проекта sassy как-то так.

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

64-бит и AVX, MMX и прочее там ЕМНИП ниасилили. а зря – подход интересный, стоило бы допилить проект.

так что чисто кукаретически и из лиспа в асм – а не только из форта в асм тоже можно раскрутиться.

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

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

вспомнил ссылку кришнакумар «Writing Your Own Toy OS (Part I)» переписано на sassy

проект называется sassy (сайт)[http://sassy.sourceforge.net/] файлы

Sassy is a portable assembler for x86 processors written in R5RS Scheme with the addition of a few SRFIs.

демо ось кришнакумарова

; A boot thingy that does nothing but display a blue "A"

; http://linuxgazette.net/issue77/krishnakumar.html

; load up sassy, then:
;
; (sassy-make-bin "boot" (sassy "boot.sassy") 'boot)
;
; dump to a floppy
;
; dd if=boot of=/dev/fd0
;
; The (es <instruction>) is a segment override prefix
; (section 16.1.1 of Volume 3 of the Intel Manuals)

(bits 16)

(text
  (mov ax #xb800)         ; load address of video memory...
  (mov es ax)             ; ...into es
  (es (mov (& 0) #x41))   ; mov "A" to byte 0 of vid-mem
  (es (mov (& 1) #x1f))   ; mov blue to byte 1 of vid-mem
  (label loop
    (jmp loop)))          ; do nothing
anonymous
()
Ответ на: комментарий от anonymous

getBalance >>= do_something_with_balance

И куда положить обработку ошибки в виде всплывающего окна с кнопками, если баланс не вернулся?

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

Exception e

И те же Fail42 только в виде

data getBalanceException = Fail42 | NoConnection5 | DBCorrupted10
data getNameException = Fail43 | BadChar4 | NoConnection6
monk ★★★★★
()
Ответ на: комментарий от monk

да, но разница в том, что rs обрабатывает все грязные ошибки, как будто они чистые, а hs тоже вроде бы не прочь так красиво жить, но вся грязь ловится Exception в монаде (чистые тоже можно)

mapException :: (Exception e1, Exception e2) => (e1 -> e2) -> a -> a 
anonymous
()
Ответ на: комментарий от anonymous

rs обрабатывает все грязные ошибки, как будто они чистые

Э… в rs же вообще понятия чистоты нет. Или как?

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

Аналог Exception в чистых функциях — монада ExceptT. Вообще, throw который кидает данные любого типа откуда угодно — жуткое нарушение типизации.

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

понятия чистоты нет

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

throw :: Exception e => e -> a

цимес в том, что ловится только в IO, а не ветра в поле

instance (MonadIO m) => MonadIO (ExceptT e m) where
    liftIO = lift . liftIO
anonymous
()
Ответ на: комментарий от monk

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

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

sum(X,Y) when is_integer(X), is_integer(Y) -> X + Y.

можно ли написать sum([1,2],[3,4])? можно, но ты получишь runtime error. можно написать так:

sum(X,Y) when is_integer(X), is_integer(Y) -> X + Y;
sum(X,Y) when is_list(X), is_list(Y) -> X ++ Y.
тогда runtime error не будет, но будет если складывать кортежы.

чудо хацкеля в том, что можно писать точно так же

data Arg a = I Int | L [a]
f (I x) (I y) = I $ x + y
f _ _ = undefined
или
data Arg a = I Int | L [a]
f (I x) (I y) = I $ x + y
f (L x) (L y) = L $ x ++ y
f _ _ = undefined
поведение такое же. единственный минус - это необходимость описывать тип, но для того, что бы писать аля ерланг нужно сделать это один раз, определив суму типов для всего, что есть в eрланге и писать ф-ии вида f :: ErlType -> ErlType

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

data Err = NoConnection | DbError | BadChar ...
getBalance :: Either (Err,String) Int
getName :: Either (Err,String) String

either show_success show_error (
getBalance >>= return . do_balance >>
getName >>= return . do_name)
и даже с том же си, коды ошибок достаточно обширное поле для исследований (в том смысле что их очень много разных). Все они «просумированны» в man errno и в то же время я уверен на все 100, fork() никогда не вернёт EBADF.

и всего вышесказанного я думаю ты и сам поймёшь ущербность и куцость динамически типизированых языков. они по своей сути просто игрушки для написания однострочников или скриптования простого поведения. другое дело язык с статической типизацией, позволяющий типами моделировать задачи. и в лиспе и в питоне тоже есть типизация, но тип всегда один и тот же, и всё приходиться моделировать парами с run time values (циферками, атомами, тегами и пр.). конечно, если бы лисп бы какой нибудь агдой или идрисом можно было бы заюзать gadt и жить поживать, но лисп - не агда, а такой себе полускомпилированый питон.

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

Все они «просумированны» в man errno и в то же время я уверен на все 100, fork() никогда не вернёт EBADF.

Но тогда мы теряем ограничения типа. То есть, уверенность как бы есть, но тип начинает позволять вернуть из fork() EBADF. То есть с таким же успехом можем вообще не ограничивать возможные ошибки и возвращать Either (String,String) a.

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

Только когда система типов достаточно мощна. Например, в Typed 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))))

В Haskell такой не написать. В Haskell даже zip не сделать нормально: приходится плодить zip3,zip4,zip5, …

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

Лиспы бывают разные. Typed Racket статически типизированный.

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

чудо хацкеля в том, что можно писать точно так же

Увы, не также. Если в erlang после того определения можно писать sum(5, 3) или sum(«o», «k»), то в Haskell придётся писать sum (I 5) (I 3) или sum (L "o") (L "k"). И этот синтаксический мусор неустраним. И ошибка по sum (I 1) (L "k") будет только в рантайме.

Хотя в Typed Racket можно делать

(: sum (case-> (-> Number Number Number)
               (-> String String String)))
(define (sum x y)
  (cond
    [(string? x) (string-append x y)]
    [else (+ x y)]))

При этом будет ошибка компиляции на (sum 1 «k») или даже на (+ 5 (sum «o» «k»)).

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

И этот синтаксический мусор неустраним

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

И ошибка по sum (I 1) (L «k») будет только в рантайме.

f :: m -> m -> m
f (I x) (I y) = I $ x + y
f (L x) (L y) = L $ x ++ y
f _ _ = _

main = f (I 1) (L [2])

компельни вот это и удивись.

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

error: Not in scope: data constructor ‘I’

Кроме того, тип main и Arg никак совпасть не может.

Если же ты имел в виду

data Arg a = I Int | L [a] deriving Show
f (I x) (I y) = I $ x + y
f (L x) (L y) = L $ x ++ y
f _ _ = undefined

main = putStrLn $ show $ f (I 1) (L [2])

то всё успешно компилируется

$ ghc test.hs
[1 of 1] Compiling Main             ( test.hs, test.o )
Linking test ...
$ ./test
test: Prelude.undefined
CallStack (from HasCallStack):
  error, called at libraries/base/GHC/Err.hs:80:14 in base:GHC.Err
  undefined, called at test.hs:4:9 in main:Main
monk ★★★★★
()
Ответ на: комментарий от anonymous

коню понятно, что так никто писать не будет

А как? В erlang’е будет что-то типа: 5*sum(x+y,z-k), В Haskell аналог будет 5*(fromI $ sum (I (x+y)) (I (z-k))).

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

так попробуй [code=haskell] f _ _ = _ [/code]

гетерогенный список можно из пар сделать. делов то. [code=haskell]

fst (1,(«hello»,(undefined))) 1 fst . snd ((1,(«hello»,(undefined))) «hello» [/code]

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

так попробуй [code=haskell] f _ _ = _ [/code]

Ошибка будет, так как значения _ нет. А что это должно было дать?

гетерогенный список можно из пар сделать

А это к чему вообще? Можно. Только написать функцию length для такого списка уже не получится. Система типов не позволит.

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

А как?

вот так попробуй

foldl1 f (map I [1,2])

тебе же нравится писать как конь.

А что это должно было дать?

скомпилировать получилось? ты ж сам писал что в рэкет такой умный, что не компилирует.

слушай, с тобой не интересно, ты упорот. продолжай ебать гусей писать на рэкете.

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

вот так попробуй

Совсем упоролся? Даже по длине строки f (I 1) (I 2) короче, чем этот крокодил.

скомпилировать получилось? ты ж сам писал что в рэкет такой умный, что не компилирует.

Не тупи.

Я написал, что Racket проверяет во время компиляции ошибки типов.

(sum 1 5) компилируется, (sum 1 "bad") не компилируется. А твой типа аналог в Haskell компилирует любые комбинации возможных типов.

P.S. Нормальное решение в Haskell с проверкой типов существует через класс типов. Но тебе только кони мерещатся…

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

Читал, читал и решил что-нить слепить. Была одна моя тема здесь, мне помогли написать одну строчку что решала мою проблему. Вот подумал, что надо бы попробовать сделать это на scheme для усвоения материала и встал в тупик. Как считать файл, как построчно его проанализировать, как скопировать файл в другой с другим именем? Одно дело последовательная теория языка, другое дело его применение. Как то не хватает чего то, типа справочника по операторам языка, чтобы можно было найти по своим нуждам. Хотя может быть это как в матане - сначала надо усвоить все на простых примерах?

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

Если именно на Racket, то всё просто:

#lang racket
(call-with-input-file "students.txt"
  (λ (in)
    (for ([line (in-lines in)])
      (copy-file "s.pdf" (string-append line ".pdf")))))

Если на чистом старом Scheme R5RS, то copy-file придётся вручную писать через чтение файла и запись.

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

https://docs.racket-lang.org/reference/index.html

Для Scheme https://schemers.org/Documents/Standards/R5RS/HTML/

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

Спасибо. Начало есть :). Ссылки я уже видел и двигаюсь помаленьку по освоению. Я не изучал программирование (кроме бейсика в студенчестве, да капельку питон) и несколько теряюсь в том как изучать. Я много лет преподаю математику и физику и вижу, что тут нужен какой то другой подход. Вот есть конкретная простая задача и я сразу в ступоре - какие операторы смогут это сделать? Может есть какая нибудь классификация по областям, что ли? Типа, действия с файлами, ввод вывод (коллекция функций), анализ файла (коллекция функций). Вроде как говорить на иностранном языке: есть мысль которая вызывает набор слов и конструкций, в рамках которых можно выразить свою мысль.

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

Может есть какая нибудь классификация по областям, что ли?

Конечно.

Типа, действия с файлами

https://docs.racket-lang.org/reference/os.html

ввод вывод

https://docs.racket-lang.org/reference/input-and-output.html

И поиск в левом верхнем углу.

В сложных случаях пишу в google что-то типа «Racket open dbf».

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

Точно, есть такой поиск, воспользуюсь. Возникает другой вопрос. Вы пишете, что в racket код имеет такой вид, а в scheme другой. Наверное есть такая возможность сделать код в racket, а трансформировать в scheme? Есть же всякие компиляторы из языка в язык.

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

Scheme более ограниченный язык. Если наоборот, то тривиально: в первой строке пишешь #lang r5rs или #lang r6rs и используешь соответствующую версию.

Есть же всякие компиляторы из языка в язык.

Нельзя скомпилировать из Питона в Бейсик. Из Racket в Scheme аналогично.

monk ★★★★★
()
Ответ на: комментарий от monk
--{-# LANGUAGE GADTs #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE MultiParamTypeClasses #-}

They All Fold (Prod. DJ Hostility)

undefined :: forall (r :: RuntimeRep) . forall (a :: TYPE r) . HasCallStack => a

Разве вы не знаете, братия, - ибо говорю знающим закон, - что закон имеет власть над человеком, пока он жив?

для любителей покукарекать на rvalues, но это один сплошной побочный эффект:

template <class... Types>
 zipper<special_decay_t<Types>...> zip(Types&&... args)
 {
   return zipper<special_decay_t<Types>...>(std::forward<Types>(args)...);
 }
 
template <class Tuple, std::size_t I, std::size_t Is...>
bool any_equals(Tuple const& lhs, Tuple const& rhs, std::index_sequence<I, Is...> ) {

    return std::get<I>(lhs) == std::get<I>(rhs) ||          
        any_equals(lhs, rhs, std::index_sequence<Is...>{});
}

template <class... Ts, std::size_t... Is>
void increment(std::tuple<Ts...>& tpl, std::index_sequence<Is...> ) {
    using expander = int[];
    expander{0,
        (void(
            ++std::get<Is>(tpl)
        ), 0)...
    };
}

template <class... Ts>
void increment(std::tuple<Ts...>& tpl) {
    increment(tpl, std::index_sequence_for<Ts...>{});
}

template<typename List,
         template<typename X, typename Y> class F,
         typename I, 
         bool = IsEmpty<List>::value>
class AccumulateT;

и это только <Zi…>&&, тут ещё как до высот, как раз к Пасхе опробуете undefined RuntimeRep и этот синтаксический мусор неустраним.

Простое решение для юных пенсионеров (типа аналог):

-- zipN :: (a -> b -> c -> r) -> c a -> c b -> .... c c ->  c r
-- c is Functor

class Zip2 c where
  zipW2 :: (a->b->w) -> c a -> c b -> c w

instance Zip2 [] where
  zipW2 = zipWith
  
zipN f c1 = zip_n (fmap f c1)

class ZipN ca r where
  zip_n :: ca -> r

instance (a ~ r) => ZipN (c a) (c r) where
  zip_n = id

instance (Zip2 c, a ~ a', ZipN (c b) r) =>
         ZipN (c (a -> b)) (c a' -> r) where
  zip_n cf ca = zip_n (zipW2 ($) cf ca)

не мучайте чёрную курочку и внутренности вавилонских девок (антропомантия) не сделать нормально: приходится плодить;

пейте нефтяной эликсир! (якобы демонстрирует недостатки швецкого дерьма)

zipWithM_ :: (Applicative m, Foldable t, Zip t) => (a -> b -> m c) -> t a -> t b -> m ()
zipWithM_ f xs ys = sequenceA_ $ Data.Semialign.zipWith f xs ys
anonymous
()
Ответ на: комментарий от anonymous

Простое решение для юных пенсионеров (типа аналог):

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

В этом смысле Typed Racket хорош тем, что его при необходимости всегда можно убедить через cast.

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

Кастую Хаос :)

Нить Ариадны не так прочна, как Золотой дождь

hlist :: [Dynamic]
hlist = [ toDyn "Ariadne's string"
        , toDyn (8 :: Int)
        , toDyn (Just "Golden Rain")
        ]

dyn = hlist !! 0

v :: Maybe String
v = case fromDynamic dyn of
        Nothing -> error "Carthago delenda est"
        Just x  -> x
anonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.