Sorting lisp格式的排序算法
我已经决定学习一些函数式语言,毕竟我已经学会了lisp模式 我正在尝试创建一个函数,它检查列表是否已排序,最低优先级是否会越高,反之亦然,如果可以排序,则应返回true或false 这是我的第一个代码,仅当列表增加(或相等)时才起作用Sorting lisp格式的排序算法,sorting,lisp,scheme,Sorting,Lisp,Scheme,我已经决定学习一些函数式语言,毕竟我已经学会了lisp模式 我正在尝试创建一个函数,它检查列表是否已排序,最低优先级是否会越高,反之亦然,如果可以排序,则应返回true或false 这是我的第一个代码,仅当列表增加(或相等)时才起作用 (定义排序? (兰姆达(lst) (cond((空的?lst)#t) (或者(你几乎把它做好了,看: (define sorted? (lambda (lst) (cond ((or (empty? lst) (empty? (cdr lst)))
(定义排序?
(兰姆达(lst)
(cond((空的?lst)#t)
(或者(你几乎把它做好了,看:
(define sorted?
(lambda (lst)
(cond ((or (empty? lst) (empty? (cdr lst)))
#t)
(else (and (<= (car lst) (cadr lst))
(sorted? (cdr lst)))))))
现在,如果您想知道列表是按升序排序还是按降序排序:
(define lst '(1 2 3 4 5))
(or (sorted? lst >=) (sorted? lst <=))
> #t
(定义lst'(1 2 3 4 5))
(或(已排序的?lst>=)(已排序的?lst#t
正如您所见,函数式编程是指尽可能将过程定义为通用的,并将它们结合起来解决问题。您可以将函数作为参数传递,这一事实对实现通用函数有很大帮助。特定实现
我会更进一步:
(define sorted? (lambda (lst)
(letrec ((sorted-cmp
(lambda (lst cmp)
(cond ((or (empty? lst) (empty? (cdr lst)))
#t)
(else (and (cmp (car lst) (cadr lst))
(sorted-cmp (cdr lst) cmp)))))))
(or (sorted-cmp lst <=) (sorted-cmp lst >=)))))
(定义已排序的?(lambda(lst)
(letrec((已排序的cmp)
(lambda(第一次cmp)
(条件((或(空?lst)(空?(cdr lst)))
#(t)
(其他(和(cmp(车辆lst)(cadr lst))
(已排序cmp(cdr lst)cmp()()())))
(或(已排序的cmp lst=()()))
此版本与his的最大区别在于sorted?
现在使用letrec
将Óscar的版本定义为一个内部帮助函数,并对其进行双向调用
功能性思维
实际上,您选择了一个很好的示例来说明Scheme如何看待世界的某些方面,并且您的实现有了一个很好的开端
解决这个问题所涉及的一个重要功能原则是,您可以将任何内容放入(**此处**更多内容”(1 2 3 4))
,您可以将其作为参数传递给另一个函数。也就是说,函数是函数式编程语言中的第一类。因此,您使用的是,我想更具体地说,您的问题的意思是,“如果我已经用命令式语言(如C或Java)编程,我如何调整函数式编程的思维?”?“以你的问题为例,我将用周六上午的时间详细回答这个问题。我将通过三个阶段跟踪函数式程序员的发展,每个阶段都是禅宗的一个连续的更高层次——1)迭代地思考;2)递归地思考;3)懒洋洋地思考
第一部分——反复思考
假设我用C语言编程,我不能也不会使用递归——也许编译器没有优化尾部递归,递归解决方案会溢出堆栈。所以我开始考虑我需要保持什么状态。我想象一台小机器在输入上爬行。它会记得它是在搜索递增还是递减asing sequence。如果它还没有决定,它会根据当前输入(如果可以的话)来决定。如果它发现输入指向错误的方向,它将以zigzag=true终止。如果它到达输入的末尾,它将以zigzag=false终止
int
zigzag(int *data, int n)
{
enum {unknown, increasing, decreasing} direction = unknown;
int i;
for (i = 1; i < n; ++i)
{
if (data[i] > data[i - 1]) {
if (direction == decreasing) return 1;
direction = increasing;
}
if (data[i] < data[i - 1]) {
if (direction == increasing) return 1;
direction = decreasing;
}
}
/* We've made it through the gauntlet, no zigzagging */
return 0;
}
现在我们需要定义最初增加
,最初减少
,减少
,和增加
。最初-
函数非常简单:
(define (initially-increasing xs)
(> (cadr xs) (car xs)))
(define (initially-decreasing xs)
(< (cadr xs) (car xs)))
我们可以编写一个类似的增加
函数,但显然只需要一个更改:
。复制这么多代码会让你感到不安。难道我不能要求语言让我的函数像减少
,而是在函数语言中使用
,您可以做到这一点,因为函数可以返回其他函数!因此我们可以编写一个函数来实现:“给定一个比较运算符,如果其参数的任意两个连续元素的比较为真,则返回一个返回真的函数。”
增加
和减少
现在都可以非常简单地定义:
(define decreases (ever <))
(define increases (ever >))
现在我需要一种方法来推导比较
,即xs
的每个成员与其后继成员的比较列表。这并不难做到,也许最好通过示例来解释
> xs
[1,1,1,2,3,4,5,3,9,9]
> zip xs (tail xs)
[(1,1),(1,1),(1,2),(2,3),(3,4),(4,5),(5,3),(3,9),(9,9)]
> map (\(x,y) -> compare x y) $ zip xs (tail xs)
[EQ,EQ,LT,LT,LT,LT,GT,LT,EQ]
这就是我们所需要的;这两行是完整的实现-
zigzag xs = LT `elem` comparisons && GT `elem` comparisons
where comparisons = map (\(x,y) -> compare x y) $ zip xs (tail xs)
我要注意的是,这个程序只通过一次列表来测试递增和递减情况
到目前为止,您可能已经想到了一个反对意见:这种方法不是很浪费吗?当它只需要搜索到第一次方向改变时,它不是要搜索整个输入列表吗?实际上,不,它不会,因为惰性评估。在上面的示例中,它计算整个比较列表是因为它必须打印出来,但是如果将结果传递给<代码>锯齿形< /代码>,它只会对比较列表进行足够的评估,以找到一个实例:<代码> GT以及<代码> Lt,并且不再进一步。要说服自己,请考虑以下情况:
> zigzag $ 2:[1..]
True
> zigzag 1:[9,8..]
True
这两种情况下的输入都是一个无限列表([2,1,2,3,4,5..]和[1,9,8,7,6,5…])。尝试将它们打印出来,它们将填满屏幕。但将它们传递到之字形
,一旦找到第一个方向变化,它将很快返回
读取代码的许多困难来自于控制流的多个分支。这些分支中的许多实际上是为了避免计算超出我们需要的量。但是,通过延迟求值可以实现许多相同的事情,使程序比原始问题更短、更真实。试试这个
(define sorted?
(lambda (l)
(cond ((null? l) #t)
(else (check-asc? (car l) (sorted? (cdr l))
(check-desc? (car l) (sorted? (cdr l))))))
(define check-asc?
(lambda (elt lst)
(cond ((null? lst) #t)
(else (or (< elt (car lst)) (= elt (car lst))) (check-asc? (car lst) (cdr lst))))))
(define check-desc?
(lambda (elt lst)
(cond ((null? lst) #t)
(else (or (< elt (car lst)) (= elt (car lst))) (check-desc? (car lst) (cdr lst))))))
(定义排序?
(λ(l)
(条件((空?l)#t)
(其他(检查asc?(车辆l)(已分拣)(c
(define decreases (ever <))
(define increases (ever >))
zigzag xs = LT `elem` comparisons && GT `elem` comparisons
> xs
[1,1,1,2,3,4,5,3,9,9]
> zip xs (tail xs)
[(1,1),(1,1),(1,2),(2,3),(3,4),(4,5),(5,3),(3,9),(9,9)]
> map (\(x,y) -> compare x y) $ zip xs (tail xs)
[EQ,EQ,LT,LT,LT,LT,GT,LT,EQ]
zigzag xs = LT `elem` comparisons && GT `elem` comparisons
where comparisons = map (\(x,y) -> compare x y) $ zip xs (tail xs)
> zigzag $ 2:[1..]
True
> zigzag 1:[9,8..]
True
(define sorted?
(lambda (l)
(cond ((null? l) #t)
(else (check-asc? (car l) (sorted? (cdr l))
(check-desc? (car l) (sorted? (cdr l))))))
(define check-asc?
(lambda (elt lst)
(cond ((null? lst) #t)
(else (or (< elt (car lst)) (= elt (car lst))) (check-asc? (car lst) (cdr lst))))))
(define check-desc?
(lambda (elt lst)
(cond ((null? lst) #t)
(else (or (< elt (car lst)) (= elt (car lst))) (check-desc? (car lst) (cdr lst))))))
(define sorted?
(lambda (l)
(cond ((null? l) #t)
(else (if (check-asc? (car l) (cdr l)) #t
(check-desc? (car l) (cdr l)))))))
(define check-asc?
(lambda (elt lst)
(cond ((null? lst) #t)
(else (if (or (< elt (car lst)) (= elt (car lst))) (check-asc? (car lst) (cdr lst))
#f)))))
(define check-desc?
(lambda (elt lst)
(cond ((null? lst) #t)
(else (if (or (> elt (car lst)) (= elt (car lst))) (check-desc? (car lst) (cdr lst))
#f)))))