LINUX.ORG.RU

Racket Scheme. Разделить каждый элемент первого списка на каждый элемент второго списка.

 ,


3

4

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



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

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

Да, конечно.

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

Попробуй переписать через let*

(define (my-turbo-cool-list-processor proc . ls)
  (define (rec r e la)
    (if (null? la)
	r
	(rec (cons (proc e
			 (car la)
			 )
		   r
		   )
	     e
	     (cdr la)
	     )
	)
    )
  (define (rec* r a lb)
    (if (null? a)
	(reverse r)
	(rec* (rec r (car a) lb)
	      (cdr a)
	      lb
	      )
	)
    )
  (define (rec** l lc)
    (if (null? lc)
	l
	(rec** (rec* '() l (car lc))
	       (cdr lc)
	       )
	)
    )
  (rec** (car ls)
	 (cdr ls)
	 )
  )


(define-syntax foo
  (syntax-rules (
		 <-
		 return
		 )

    ((_) '())

    ((_ exp) exp)
        
    ((_ (exp ...) r ...)
     ((lambda () (exp ...) (foo r ...) )
      )
     )

    ((_ v <- exp r ...)
     ((lambda (v) (foo r ...)) exp)
     )

    ((_ return (proc some ...) r ...)
     (my-turbo-cool-list-processor proc some ...)
     )
    
    )
  )

> (foo
 (display 'FOO) (newline)
 a <- '(1 2 3)
 (display 'BAR) (newline)
 b <- '(4 5)
 b <- (append b b)
 return (cons a b)
 (display 'BAZ)
 )


FOO
BAR
((1 . 4) (1 . 5) (1 . 4) (1 . 5) (2 . 4) (2 . 5) 
(2 . 4)                                         
  (2 . 5) (3 . 4) (3 . 5) (3 . 4) (3 . 5))
>
anonymous
()
Ответ на: комментарий от anonymous

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

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

> (foo
 (display 'FOO) (newline)
 a <- '(1 2 3)
 (display 'BAR) (newline)
 b <- '(4 5)
 b <- (append b b)
 return (* 2 (+ a b))
 (display 'BAZ)
 )

FOO
BAR
. . +: contract violation
  expected: number?
  given: '(1 2 3)
  argument position: 1st
  other arguments...:

Если нужны монады на Racket, то вот: https://gist.github.com/tonyg/1da999c770a363c62969

И работает превосходно

> (do a <- '(1 2 3) b <- '(4 5) (return (* 2 (+ a b))))
'(10 12 12 14 14 16)
> (do a <- '(1 2 3) b <- '(4 5) b <- (list b b) (return (* 2 (+ a b))))
'(10 10 12 12 12 12 14 14 14 14 16 16)
monk ★★★★★
()
Ответ на: комментарий от monk

портянки

так это типа реализация ‘do’, я что каждый раз макрос должен переписываить? А почему return в хаскеле делает тройной фолд для списков я хз. Что просили, то и написал.

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

во-первых можно сделать вот так:

(foo
 a <- '(1 2 3)
 b <- '(4 5)
 (define (my-ultra-cool-thunk a b)
   (* 2 (+ a b)))
 return (my-ultra-cool-thunk a b)
 (display 'BAZ)
 )

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

((_ names (values ...) return (body ...) r ...)
 ((lambda names body ...) values ...)
 )

Всё. Можно наворотить чего угодно, если совсем упороться - даже свой expand-eval грязный, а внём почти произвольный синтаксис, очень переносимо будет. Гвоздями ничего не прибито, в сущности - монада, если ‘do’ принято назвать монадой.

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

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

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

так это типа реализация ‘do’, я что каждый раз макрос должен переписываить? А почему return в хаскеле делает тройной фолд для списков я хз. Что просили, то и написал.

return в хаскеле для списка создаёт список из одного элемента.

do { x <- [1,2,3]; y<-[5,6,7]; [x+y] }
==
[6,7,8,7,8,9,8,9,10]

А разворачивается это в

[1,2,3] >>= \x -> [5,6,7] >>= \y -> [x+y]

С учётом того, что для списков xs >>= f = [y | x <- xs, y <- f x], то получаем

[1,2,3] >>= \x -> [5,6,7] >>= \y -> [x+y]
==
[r1 | x <- [1,2,3], r1 <- [5,6,7] >>= \y -> [x+y]]
==
[r1 | x <- [1,2,3], r1 <- [r2 | y <- [5,6,7], r2 <- [x+y]]]
==
[r1 | x <- [1,2,3], r1 <- [x+y | y <- [5,6,7]]]
==
[x+y | x <- [1,2,3], y <- [5,6,7]]

Вот он весь do по ссылке

(define-syntax do
  (syntax-rules (<-)
    [(_ mexp) mexp]
    [(_ #:let [pat exp] rest ...)
     (match-let ((pat exp)) (do rest ...))]
    [(_ pat <- mexp rest ...)
     (bind mexp (match-lambda
                 [pat (do rest ...)]
                 [_ (fail "monadic (do) pattern failure: ~v" #'pat)]))]
    [(_ #:guard exp rest ...)
     (if exp (do rest ...) (fail "monadic (do) guard failed: ~v" #'exp))]
    [(_ mexp rest ...)
     (bind mexp (lambda (ignored) (do rest ...)))]))

Кстати, возвращать из do не обязательно один return, можно любую монаду:

do { x <- [1,2,3]; y<-[5,6,7]; return (x+y) <> return (x-y) }
==
[6,-4,7,-5,8,-6,7,-3,8,-4,9,-5,8,-2,9,-3,10,-4]
monk ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.