Следующая страница > 1 < [2] [3]

Автор Сообщение

joba

Members


Статус

157 сообщений

Где: ---
Род занятий:
Возраст:

#5615   2012-01-28 06:03 GMT+3 часа(ов)      
Очень не хватает сабжа. Например, в схеме нельзя так делать:
(define bar (map foo))
(bar '(1 5 7))

(define (f x y) (+ x y))
(define g (f 5))
 

Приходится писать так:
(define (bar lst) (map foo lst))
(bar '(1 5 7))

(define (f x y) (+ x y))
(define (g y) (f 5 y))

И было бы хорошо, если бы каждая функция была на самом деле функцией от одного аргумента:
 
(define (foo x) (lambda (y) (lambda (z) (* x y z))))
(foo 5 6)
(foo 1 2 3)

А приходится писать так:
(define (foo x) (lambda (y) (lambda (z) (* x y z))))
((foo 5) 6)
(((foo 1) 2) 3)

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

отредактировал(а) joba: 2012-01-28 06:14 GMT+3 часа(ов)

joba

Members


Статус

157 сообщений

Где: ---
Род занятий:
Возраст:

#5616   2012-01-28 06:22 GMT+3 часа(ов)      
И еще меня вот эта вот наркоманская фигня бесит в cl:
 * (car nil)
NIL
* (cdr nil)
NIL
 
Еле сдерживаю рвотные позывы.

Kergan

Members


Статус

300 сообщений

Где: ---
Род занятий:
Возраст:

#5617   2012-01-28 14:24 GMT+3 часа(ов)      
> Собственно вопрос, какие есть разумные причины существования данного безобразия в лиспах?

Отсутствие статической типизации. Без нее неясно, что значит (map foo) - частичное применение или полную аппликацию.

misha

Moderators


Статус

1275 сообщений
http://racket-lang.org/
Где: Yemen
Род занятий:
Возраст:

#5619   2012-01-28 21:40 GMT+3 часа(ов)      
($define ($map f a) (map f a))
($define (f a b c) (+ a b c))
($call f 1 2 3) ; => 6
(define g (f 5)) ; => #<procedure>
(define (1+ a) (+ a 1))
(define bar ($map 1+))
(bar '(1 5 7)) ; => '(2 6 8)

joba

Members


Статус

157 сообщений

Где: ---
Род занятий:
Возраст:

#5620   2012-01-28 21:59 GMT+3 часа(ов)      
>Отсутствие статической типизации. Без нее неясно, что значит (map foo) - частичное применение или полную аппликацию.

Причем тут статическая типизация? Кому не ясно? Интерпретатору не ясно? Очень даже ясно.

joba

Members


Статус

157 сообщений

Где: ---
Род занятий:
Возраст:

#5621   2012-01-28 22:18 GMT+3 часа(ов)      
2 misha
Что это? Пример работы костыля? Как костыль написать я и сам знаю.

>(define (1+ a) (+ a 1))

Лучше (define 1+ (sum2 1)), где sum2 - бинарная операция сложения.

misha

Moderators


Статус

1275 сообщений
http://racket-lang.org/
Где: Yemen
Род занятий:
Возраст:

#5622   2012-01-28 23:09 GMT+3 часа(ов)      
> Как костыль написать я и сам знаю.

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

> Лучше (define 1+ (sum2 1)), где sum2 - бинарная операция сложения.
($define (sum2 a b) (+ a b))
(define 1+ (sum2 1))
(define bar ($map 1+))
(bar '(1 5 7)) ; => '(2 6 8)

joba

Members


Статус

157 сообщений

Где: ---
Род занятий:
Возраст:

#5624   2012-01-28 23:50 GMT+3 часа(ов)      
Единственная причина (которую я не считаю разумной), которую я вижу, - это то, что если мы делаем в языке возможными частичные аппликации, то тогда нам придется отказаться от функций с переменным числом аргументов. Но это не создает больших проблем, потому что можно передавать список как аргумент (именно поэтому я и не считаю эту причину разумной).
Например,
;sum : (List Number) -> Number
(define sum (fold1 sum2 0))
 
где под fold1 я подразумеваю левостороннюю свертку, которая принимает только один список.

misha

Moderators


Статус

1275 сообщений
http://racket-lang.org/
Где: Yemen
Род занятий:
Возраст:

#5625   2012-01-29 01:06 GMT+3 часа(ов)      
Можно обойтись и без свертки
($collect sum2 1 2 3 4 5) ; => 15
($define (div2 a b) (/ a b))
($collect div2 1 2 3 4) ; => 1/24

А нужна ли поддержка переменного числа аргументов?
($collect sum2 1 2 3 4 5) =>
((sum2 ((sum2 ((sum2 ((sum2 1) 2)) 3)) 4)) 5)

joba

Members


Статус

157 сообщений

Где: ---
Род занятий:
Возраст:

#5627   2012-01-29 02:21 GMT+3 часа(ов)      
Нет, никаких $collect быть не должно в языке. Я хочу чтоб было так:
(-> t1 t) ;контракт для лямбда-абстракции ниже (t1, t - контракты)
(lambda a b) ;лямбда-абстракция, один аргумент(a - символ,b - выражение)
 
;синтаксический сахар
(-> t1 (-> t2 (-> t3 t))) ~ (-> t1 t2 t3 t)
(lambda a1 (lambda a2 (lambda a3 b))) ~ (lambda (a1 a2 a3) b)
 
;еще синтаксический сахар
Если f : (-> t1 t2 t3 t), то
(f a1) : (-> t2 t3 t)
((f a1) a2) ~ (f a1 a2) : (-> t3 t)
((f a1 a2) a3) ~ (f a1 a2 a3) : t
 
;Создание глобальных имен:
(define name val) ;name - символ, val - выражение
(define f (lambda a b)) ;f - символ
 
;синтаксический сахар
(define f (lambda (a1 a2 a3) b)) ~ (define (f a1 a2 a3) b) ~
~ (define (f a1 a2) (lambda a3 b))
 

И да, я это уже все реализовал (кроме контрактов), но суть треда не в этом.

Kergan

Members


Статус

300 сообщений

Где: ---
Род занятий:
Возраст:

#5628   2012-01-29 21:18 GMT+3 часа(ов)      
Цитата
Причем тут статическая типизация? Кому не ясно? Интерпретатору не ясно?

Ни интерпретатору, ни компилятору

Цитата
Очень даже ясно.

Хорошо, ты видишь форму (f x) скажи, что это - аппликация или частичное применение?

И это не говоря уже обо всяких (+ х).

Цитата
Если f : (-> t1 t2 t3 t), то

Если компилятору известно, что f : (-> t1 t2 t3 t), то ЯП статически типизрован, ты в курсе? Y-комбинатор в таком лиспе, кстати, ты написать уже не сможешь.

отредактировал(а) Kergan: 2012-01-29 21:26 GMT+3 часа(ов)

joba

Members


Статус

157 сообщений

Где: ---
Род занятий:
Возраст:

#5629   2012-01-30 02:48 GMT+3 часа(ов)      
>Хорошо, ты видишь форму (f x) скажи, что это - аппликация или частичное применение?

Смотря что из себя представляет f.

Kergan

Members


Статус

300 сообщений

Где: ---
Род занятий:
Возраст:

#5630   2012-01-30 11:47 GMT+3 часа(ов)      
> Смотря что из себя представляет f.

А компилятор не знает, что из себя представляет f. И узнать никак не может.
(lambda (g f) (f 1)), например. Неизвестно же, что будет передано потом в эту лямбду.

joba

Members


Статус

157 сообщений

Где: ---
Род занятий:
Возраст:

#5631   2012-01-30 20:38 GMT+3 часа(ов)      
Ну вот когда будет передано, тогда и узнает. Нам же не надо вычислять тело лямбды до того, как будет уточнен ее аргумент. И, кстати, я говорил про интерпретатор, а не компилятор. И я уже написал этот интерпретатор, а ты мне говоришь, что это невозможно. Весело бля.

Kergan

Members


Статус

300 сообщений

Где: ---
Род занятий:
Возраст:

#5632   2012-01-30 21:39 GMT+3 часа(ов)      
Цитата
Ну вот когда будет передано, тогда и узнает.

Но ведь в рантайме это будет медленно? Решил потестить реализацию на case-lambda в Racket - забавные результаты:
 
#lang racket
(require (for-syntax syntax/parse
srfi/1))
 
(define-syntax ($case-lambda stx)
(syntax-parse stx
[($case-lambda (name arg1 arg ... arg2) (args ...) body ...)
(with-syntax ([((left ...) ...) (map reverse (pair-fold cons '() (reverse (syntax->list #'(arg1 arg ...)))))]
[((right ...) ...) (reverse (pair-fold cons '() (syntax->list #'(arg ... arg2))))])
#'(case-lambda
[(left ...) (let ([curried ($case-lambda (name right ...) (args ...) (name args ...))])
curried)] ...
[(arg1 arg ... arg2) body ...]))]
[($case-lambda (name arg1) (args ...) body ...)
#'(let ([curried (lambda (arg1) (name args ...))])
curried)]))
 
 
(define-syntax ($define stx)
(syntax-parse stx
[(_ (name:id arg1:id arg:id ... arg2:id) body:expr ...+)
#'(define name ($case-lambda (name arg1 arg ... arg2) (arg1 arg ... arg2) body ...))]
[(_ (name:id arg:id ...) body:expr ...+)
#'(define (name arg ...) body ...)]))
 

это код, соответственно:
 
($define (f x y z t) (+ x y z t))
(f 1 1 1 1)
((f 1) 1 1 1)
((f 1 1) 1 1)
(((f 1) 1) 1 1)
((f 1 1 1) 1)
(((f 1) 1 1) 1)
(((f 1 1) 1) 1)
((((f 1) 1) 1) 1)
 
->
4
4
4
4
4
4
4
4
 

все работает. А теперь тесты:
 
($define (g x y) (+ x y))
 
(time (for ([i 10000000]) (+ i i)))
(time (for ([i 10000000]) (g i i)))
(time (for ([i 10000000]) ((g i) i)))
 
->
cpu time: 1156 real time: 1195 gc time: 0
cpu time: 1172 real time: 1207 gc time: 0
cpu time: 1203 real time: 1247 gc time: 0
 

Короче, инлайнинг байткода в racket - это нечто!
Ладно, второй вариант совпадает с первым (понятно, что компилятор просто подставил нужную форму), но во третьем случае даже лямбда при частичном применении в (g i) не создавалась! Он и ее раскрыл и заинлайнил на ходу
Вырубаем инлайнинг:
 
($define (g x y) (+ x y))
(define-values (f1 f2) (values #f #f))
(set!-values (f1 f2) (values + g))
(time (for ([i 10000000]) (f1 i i)))
(time (for ([i 10000000]) (f2 i i)))
(time (for ([i 10000000]) ((f2 i) i)))
 
->
cpu time: 1766 real time: 1806 gc time: 0
cpu time: 1500 real time: 1561 gc time: 0
cpu time: 2235 real time: 2307 gc time: 328
 

Теперь уже лямбда создается. Можно обратить внимание - вторйо вариант быстрее первого, т.к. + так же определяется в виде case-lambda, но там больше кейзов (для rest аргумента).

для сравнения вариант с "чистым" сложением:
 
(time (for ([i 10000000]) (unsafe-fx+ i i)))
 
->
cpu time: 1187 real time: 1233 gc time: 0
 


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

misha

Moderators


Статус

1275 сообщений
http://racket-lang.org/
Где: Yemen
Род занятий:
Возраст:

#5633   2012-01-31 00:45 GMT+3 часа(ов)      
2Kergan

Какой смысл в "(let ([curried ...]) curried)", его ведь упразднит оптимизатор?

> но во третьем случае даже лямбда при частичном применении в (g i) не создавалась! Он и ее раскрыл и заинлайнил на ходу

Это неудивительно, если учесть, что функция объявлена в модуле, а не в рантайме. А также она ни разу не переопределялась.
(time (for ([i 10000000]) (+ i i)))
(time (for ([i 10000000]) (g i i)))
(time (for ([i 10000000]) ((g i) i)))
 
(displayln (make-string 50 #\*))
 
(set! g g)
(collect-garbage)
(time (for ([i 10000000]) (+ i i)))
(time (for ([i 10000000]) (g i i)))
(time (for ([i 10000000]) ((g i) i)))
 
cpu time: 1109 real time: 1110 gc time: 0
cpu time: 1375 real time: 1375 gc time: 0
cpu time: 1922 real time: 1953 gc time: 62
**************************************************
cpu time: 1187 real time: 1234 gc time: 0
cpu time: 1547 real time: 1547 gc time: 0
cpu time: 2063 real time: 2188 gc time: 61

отредактировал(а) misha: 2012-01-31 01:00 GMT+3 часа(ов)

Kergan

Members


Статус

300 сообщений

Где: ---
Род занятий:
Возраст:

#5635   2012-01-31 06:56 GMT+3 часа(ов)      
Цитата
Какой смысл в "(let ([curried ...]) curried)", его ведь упразднит оптимизатор?

у функции будет имя <curried> тогда, а не <procedure module line-number column-number>. Вообще, там по-хорошему должно быть что-то типа <curried-name module line-number column-number> (это все для отладки), но мне было лень, оставил так
Хотя вообще можно inferred-name и напрямую в синтаксический объект для лямбды добавить.

Цитата

cpu time: 1109 real time: 1110 gc time: 0
cpu time: 1375 real time: 1375 gc time: 0
cpu time: 1922 real time: 1953 gc time: 62

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

отредактировал(а) Kergan: 2012-01-31 07:20 GMT+3 часа(ов)

misha

Moderators


Статус

1275 сообщений
http://racket-lang.org/
Где: Yemen
Род занятий:
Возраст:

#5636   2012-01-31 15:10 GMT+3 часа(ов)      
> у тебя, видимо, инлайнинг и так вырублен.

Компилятор учитывает наличие переопределения (set! g g), поэтому не производит инлайнинг функции. Это возможно, ведь в рэкете модуль компилируется целиком, а не по частям (как в лиспе), поэтому возможен предпросмотр и продвинутые оптимизации.
($define (g x y) (+ x y))
(time (for ([i 10000000]) (+ i i)))
(time (for ([i 10000000]) (g i i)))
(time (for ([i 10000000]) ((g i) i)))

cpu time: 1109 real time: 1109 gc time: 0
cpu time: 1125 real time: 1125 gc time: 0
cpu time: 1110 real time: 1110 gc time: 0

Kergan

Members


Статус

300 сообщений

Где: ---
Род занятий:
Возраст:

#5641   2012-01-31 18:14 GMT+3 часа(ов)      
Цитата
Компилятор учитывает наличие переопределения (set! g g), поэтому не производит инлайнинг функции.

ну да, все правильно, мне просто почему-то показалось, что он не должен инлайнить только после set!.

Кстати, в какой-то из последних версий добавили cross-module инлайнинг.

misha

Moderators


Статус

1275 сообщений
http://racket-lang.org/
Где: Yemen
Род занятий:
Возраст:

#5657   2012-02-03 13:53 GMT+3 часа(ов)      
> Кстати, в какой-то из последних версий добавили cross-module инлайнинг.

Не в курсе.

joba

Members


Статус

157 сообщений

Где: ---
Род занятий:
Возраст:

#5659   2012-02-03 17:01 GMT+3 часа(ов)      
Есть идея создать такой диалект лиспа (правда от лиспа там останется только синтаксис - s-выражения): смесь идей из kernel (первоклассность всего и вся), racket (контракты, модульность, pattern matching), haskell (строки в виде списков символов, частичное применение, встроенное каррирование, ленивые вычисления (я не имею в виду те костыли, что в scheme), вывод "типов" (в нашем случае контрактов), чистота (через монады или что-нибудь похожее)). Может еще что-нибудь. Потом, возможно, создам отельную тему, когда реализую это все, если, конечно, это кому-то будет интересно.

misha

Moderators


Статус

1275 сообщений
http://racket-lang.org/
Где: Yemen
Род занятий:
Возраст:

#5668   2012-02-04 00:09 GMT+3 часа(ов)      
Если тебе он нужен, то можешь реализовать. А так... есть Shen
(1+) +
+ : (number --> (number --> number))
 
(2+) a
a : symbol
 
(3+) 1.2
1.2 : number
 
(4+) (+ 1)
#<FUNCTION :LAMBDA (#:Y18385) (add #:Y18384 #:Y18385)> : (number --> number)
 
(5+) (+ 1 2 3)
6 : number
 
(6+) (((+ 1) 2) 3)
type error
 
(7+) ((+ 1) 2)
3 : number
 
(8+) [1 2 3 | [1 2 3]]
[1 2 3 1 2 3] : (list number)
 
(9+) (define factorial
{number --> number}
0 -> 1
N -> (* N (factorial (- N 1))))
factorial : (number --> number)
 
(10+) (factorial 10)
3628800 : number
 

joba

Members


Статус

157 сообщений

Где: ---
Род занятий:
Возраст:

#5670   2012-02-04 02:37 GMT+3 часа(ов)      
Shen отвратителен. Во-первых, он статически типизированный. И при этом хуже haskell по всем параметрам => на фиг не нужен.
Во-вторых, pattern matching убогий, он такой не нужен из коробки.
В-третьих, синтаксис довольно далек от чистого s-expressions. Т.е. грязь. Должны быть в основе либо чистые s-выражения, либо что-то типа навороченного хаскелльного синтаксиса. Что-то промежуточное, совмещающее и то и другое понемножку - бессмысленное убожество.
В-четвертых, костыльное call-by-need, как в scheme.
В-пятых, есть макросы - не первоклассные объекты.
В-шестых, в eval нельзя передать окружение.
В-седьмых, есть строки как базовый тип объектов - лишняя сущность.
Короче, этот Shen вдоль и поперек сплошное говно.

joba

Members


Статус

157 сообщений

Где: ---
Род занятий:
Возраст:

#5671   2012-02-04 03:20 GMT+3 часа(ов)      
Кстати, если кто-то подумал, что поддержка всех фич, которые я перечислил в Сообщение #5659, предполагает статическую типизацию, то он дурак. Весь checking будет производиться в рантайме. Вывод "типов" тоже. Декларации вида (: name contract), которые должны делаться до (define name val), не обязательны. Сhecking будет опциональным, он нужен только на этапе разработки, в готовом продукте он не нужен.

Kergan

Members


Статус

300 сообщений

Где: ---
Род занятий:
Возраст:

#5673   2012-02-04 08:39 GMT+3 часа(ов)      
Цитата
смесь идей из kernel (первоклассность всего и вся)

в чем именно проявляется первоклассность kernel по сравнению с другими диалектами?

joba

Members


Статус

157 сообщений

Где: ---
Род занятий:
Возраст:

#5674   2012-02-04 11:39 GMT+3 часа(ов)      

misha

Moderators


Статус

1275 сообщений
http://racket-lang.org/
Где: Yemen
Род занятий:
Возраст:

#5675   2012-02-04 14:11 GMT+3 часа(ов)      
> Во-первых, он статически типизированный.

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

> Во-вторых, pattern matching убогий, он такой не нужен из коробки.

Для игрушечного языка вполне нормальный. Реализуешь лучше?

> В-третьих, синтаксис довольно далек от чистого s-expressions.

Обоснуй.

> В-четвертых, костыльное call-by-need, как в scheme.

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

> В-пятых, есть макросы - не первоклассные объекты.

Разделение пространств имен - это правильный шаг.

> В-шестых, в eval нельзя передать окружение.

А зачем? Eval использует текущее пространство имен.

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

Обоснуй.

Kergan

Members


Статус

300 сообщений

Где: ---
Род занятий:
Возраст:

#5676   2012-02-04 15:13 GMT+3 часа(ов)      
Цитата
А зачем?

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

Цитата
Обоснуй.


ну например в определении факториала твоем не проставлены скобки вокруг "0 -> 1" и "N -> (* N (factorial (- N 1)))" , которые должны там быть.

misha

Moderators


Статус

1275 сообщений
http://racket-lang.org/
Где: Yemen
Род занятий:
Возраст:

#5677   2012-02-04 15:21 GMT+3 часа(ов)      
> За тем, чтобы можно было исполнять формы в любом окружении (возможно, только что созданном в рантайме).

Ну так в чем проблема? Это ведь легко реализовать.

> ну например в определении факториала твоем не проставлены скобки

define - это ридер-макрос, т.е. ридер преобразует его в s-выражение.

P.S. Shen - это конструктор лего.

Kergan

Members


Статус

300 сообщений

Где: ---
Род занятий:
Возраст:

#5678   2012-02-04 15:24 GMT+3 часа(ов)      
Цитата
joba :
2Kergan
http://web.cs.wpi.edu/~jshutt/kernel.html


а примеры есть какие-нибудь? Типа "вот так можно в кернел и нельзя в других лиспах".


Онлайн :

0 пользователь(ей), 27 гость(ей) :




Реклама на сайте: