Если я правильно понимаю, что вы делаете, p
является предикатом, и вы разделили список l
в соответствии с этим, агрегируя ваши два результирующих списка с функцией агрегации k
; в псевдокоде:
(split-by l p k) => (k {x in l | !p(x)} {x in l | p(x)})
Проблема при замене let
в том, что функция loop
рекурсивно определена. Она имеет вид:
(define (loop low high lst)
(cond
((null? lst) <some value>)
(<some predicate> (loop (cons (car lst) low) high (cdr lst)))
(else (loop low (cons (car lst) high) (cdr lst)))))
Вы абсолютно можете использовать это непосредственно в функции, определяя «внутреннее» рекурсивную часть, но это не может быть сделано с помощью простой lambda
без let
: функция должна относиться к себе (так как он рекурсивный), и вы можете сделать это, назначив ему имя. define
сделает это, let
позволит вам это сделать, но независимо от того, как вы его поворачиваете, вам нужна эта самореклама. Если ты умный и передать в продолжение:
(lambda (low high lst cont)
(cond
((null? lst) (agg high lst))
((pred? (car lst)) (cont low (cons (car lst) high) (cdr lst) cont))
(else (cont (cons (car lst) low) high (cdr lst) cont))))
Вы удалили что самореференция, сделав его явным, но что вы передаете в качестве cont
? Ну, если вы назначили, что через позволение, у вас есть символ отсылая к нему:
(define (split-by2 lst pred? agg)
(let ((f (lambda (low high lst cont)
(cond
((null? lst) (agg low high))
((pred? (car lst)) (cont low (cons (car lst) high) (cdr lst) cont))
(else (cont (cons (car lst) low) high (cdr lst) cont))))))
(f '() '() lst f)))
Или более сжато с define
, который делает ту же самую вещь (без необходимости проходить в продолжении):
(define (split-by3 lst pred? agg)
(define (f low high lst)
(cond
((null? lst) (agg low high))
((pred? (car lst)) (f low (cons (car lst) high) (cdr lst)))
(else (f (cons (car lst) low) high (cdr lst)))))
(f '() '() lst))
Все они работают аналогично:
(split-by '(1 2 3 4) (lambda (x) (> x 2)) list)
=> ((2 1) (4 3))
(split-by2 '(1 2 3 4) (lambda (x) (> x 2)) list)
=> ((2 1) (4 3))
(split-by3 '(1 2 3 4) (lambda (x) (> x 2)) list)
=> ((2 1) (4 3))
Но вы не можете уйти с определением символа для рекурсивного FUNC Тион *.
Относительно того, почему ваш пример не работает, она работает прекрасно, за исключением того, что она создает функцию, взяв в качестве аргумента функцию (который я назвал cont
выше) и применяя логику , учитывая, что функция loop
. Поскольку у вас тогда нет «цикла», чтобы передать его (так как вы его не связали), он возвращает эту функцию и ничего не предпринимает (кроме того, в ваших возвращенных lambda
, low
и high
не определены).
* Это не совсем так, как вы могли сделать это с помощью combinators на вашем лямбда, но это сделало бы его гораздо более сложным, чем он должен:
(define Y
(lambda (h)
((lambda (x) (x x))
(lambda (g)
(h (lambda args (apply (g g) args)))))))
(define (split-ycomb lst pred? agg)
((Y
(lambda(f)
(lambda (low high l)
(cond
((null? l) (agg low high))
((pred? (car l)) (f low (cons (car l) high) (cdr l)))
(else (f (cons (car l) low) high (cdr l)))))))
'() '() lst))
Или даже уродливее чище версия, с инлайн комбинатора:
(define (split-ycomb2 lst pred? agg)
(((lambda (h)
((lambda (x) (x x))
(lambda (g)
(h (lambda args (apply (g g) args))))))
(lambda(f)
(lambda (low high l)
(cond
((null? l) (agg low high))
((pred? (car l)) (f low (cons (car l) high) (cdr l)))
(else (f (cons (car l) low) high (cdr l)))))))
'() '() lst))
Какая работа, как и ожидалось (благодаря слоям Ла mbdas):
(split-ycomb '(1 2 3 4) (lambda (x) (> x 2)) list)
=> ((2 1) (4 3))
(split-ycomb2 '(1 2 3 4) (lambda (x) (> x 2)) list)
=> ((2 1) (4 3))
Я считаю, что вы думаете о превращении '(пусть ((x E1)) E2) 'in' ((lambda (x) E2) E1) '. Это преобразование не относится к «named let». – molbdnilo
вы исправить это с помощью *** 'fix' ***. :) –
@molbdnilo [Вы можете конвертировать именованное 'let' в' rec' + 'lambda'] (http://qr.ae/RUymgf), но' rec' по-прежнему использует 'letrec' за кулисами. :-) –