Functional programming Scheme-达到一定值的斐波那契数列表

Functional programming Scheme-达到一定值的斐波那契数列表,functional-programming,scheme,fibonacci,Functional Programming,Scheme,Fibonacci,我试图编写一个函数,创建一个斐波那契序列列表,但当列表中找到某个值时停止,然后返回该列表(我希望这是有意义的) 例如,如果我给它fib list(55),函数应该返回: (11 2 3 5 8 13 21 34 55) 所以这不是我想要的第55个斐波那契数,它的值是55 到目前为止,我用于返回列表的代码如下所示: ; Create a list of the fibonacci sequence up to n. (define (fib-list n) ; n = n, f2 = 1, f

我试图编写一个函数,创建一个斐波那契序列列表,但当列表中找到某个值时停止,然后返回该列表(我希望这是有意义的)

例如,如果我给它fib list(55),函数应该返回:
(11 2 3 5 8 13 21 34 55)

所以这不是我想要的第55个斐波那契数,它的值是55

到目前为止,我用于返回列表的代码如下所示:

; Create a list of the fibonacci sequence up to n.
(define (fib-list n)
  ; n = n, f2 = 1, f1 = 1, fs = a list.
  (let loop ((n n) (f2 1) (f1 1) (fs (list)))
    (cond
      ; If n = 0, return reversed list.
      ((zero? n) (reverse fs))
      ; Check if n is in list. If so, return list.
      ((equal? n (car fs)) fs)
      ;Else, find the next fibonacci number and add it to the list.
      (else (loop (- n 1) f1 (+ f2 f1) (cons f2 fs))))))

(display (fib-list 55))
我的主要问题是查找列表中是否有一个元素,因为此时我在尝试编写
((equal?
语句)的行上遇到了一个错误

错误显示:

mcar: contract violation
  expected: mpair?
  given: '()
我对Scheme还是非常陌生,所以我对语言的整体理解不是很好。所以请温和地告诉我为什么我的代码很糟糕/没有意义。

汽车的
功能出了什么问题?
car
函数获取列表的第一个元素,但如果列表为空,则没有第一个元素。
fs
列表开始时为空。当您尝试获取空列表的第一个元素时,会收到以下错误消息:

> (car (list))
mcar: contract violation
  expected: mpair?
  given: ()
如果列表不是空的,那么它有第一个元素,这很好:

> (car (list 4 5 6))
4
按照你在评论中的意思 然而,您的评论“检查n是否在列表中”使我相信
(equal?n(car fs))
不是您想要的。用于确定元素是否在列表中的函数被调用

因此,将
(equal?n(car fs))
测试替换为
(member n fs)
,您的代码如下所示:

; Create a list of the fibonacci sequence up to n.
(define (fib-list n)
  ; n = n, f2 = 1, f1 = 1, fs = a list.
  (let loop ((n n) (f2 1) (f1 1) (fs (list)))
    (cond
      ; If n = 0, return reversed list.
      ((zero? n) (reverse fs))
      ; Check if n is in list. If so, return list.
      ((member n fs) fs)
      ;Else, find the next fibonacci number and add it to the list.
      (else (loop (- n 1) f1 (+ f2 f1) (cons f2 fs))))))

> (fib-list 55)
(10946 6765 4181 2584 1597 987 610 377 233 144 89 55 34 21 13 8 5 3 2 1 1)
这不是你想要的答案;你想要的是
(1112355813213455)

为什么列表超过了
55
? 其中一个问题是
n
被隐藏,其方式与此表达式中的方式相同:

> (let ([n 5])
    (let ([n 10])
      n))
10
正文中的
n
指的是
10
,而不是
5

结果超过了
55
,因为循环内部
n
被阴影覆盖,变成了一个不同的数字。我猜在你关于“检查n是否在列表中”的评论中,你的意思是“检查原始n是否在列表中”。为此,你必须重命名
n
s中的一个:

> (let ([orig-n 5])
    (let ([n 10])
      orig-n))
5
在代码的上下文中:

; Create a list of the fibonacci sequence up to n.
(define (fib-list orig-n)
  ; n = n, f2 = 1, f1 = 1, fs = a list.
  (let loop ((n orig-n) (f2 1) (f1 1) (fs (list)))
    (cond
      ; If n = 0, return reversed list.
      ((zero? n) (reverse fs))
      ; Check if orig-n is in list. If so, return list.
      ((member orig-n fs) fs)
      ;Else, find the next fibonacci number and add it to the list.
      (else (loop (- n 1) f1 (+ f2 f1) (cons f2 fs))))))

> (fib-list 55)
(55 34 21 13 8 5 3 2 1 1)
颠倒 这更接近,但它是相反的。您有两个基本情况,即
(zero?n)
情况和
(member orig-n fs)
情况。在其中一个情况下,它是相反的,而在其中一个情况下,它不是。将它们都更改为调用reverse可以修复它:

; Create a list of the fibonacci sequence up to n.
(define (fib-list orig-n)
  ; n = n, f2 = 1, f1 = 1, fs = a list.
  (let loop ((n orig-n) (f2 1) (f1 1) (fs (list)))
    (cond
      ; If n = 0, return reversed list.
      ((zero? n) (reverse fs))
      ; Check if orig-n is in list. If so, return reversed list.
      ((member orig-n fs) (reverse fs))
      ;Else, find the next fibonacci number and add it to the list.
      (else (loop (- n 1) f1 (+ f2 f1) (cons f2 fs))))))

> (fib-list 55)
(1 1 2 3 5 8 13 21 34 55)
小数目 这在像
55
这样的大斐波那契数上是正确的,但在小数上它仍然会做一些奇怪的事情:

> (fib-list 2)
(1 1)
> (fib-list 3)
(1 1 2)
如果您只希望它在到达
orig-n
时停止,那么可能不需要递减
n
参数,实际上使它停止得太早。删除它(并删除其零检查)会使
成员检查唯一停止的情况

这是很危险的,因为如果你给它一个非斐波那契数作为输入,它可能会进入一个无限循环。但是,它修复了一些小数字示例:

; Create a list of the fibonacci sequence up to n.
; The `orig-n` MUST be a fibonacci number to begin with,
; otherwise this loops forever.
(define (fib-list orig-n)
  ; f2 = 1, f1 = 1, fs = a list.
  (let loop ((f2 1) (f1 1) (fs (list)))
    (cond
      ; Check if orig-n is in list. If so, return reversed list.
      ((member orig-n fs) (reverse fs))
      ;Else, find the next fibonacci number and add it to the list.
      (else (loop f1 (+ f2 f1) (cons f2 fs))))))

> (fib-list 55)
(1 1 2 3 5 8 13 21 34 55)
> (fib-list 2)
(1 1 2)
> (fib-list 3)
(1 1 2 3)
最后,考虑一下发生了什么事情,如果你给它一个数字,比如<代码> 56 /代码>。
> (fib-list 56)
;infinite loop
这是一个您尚未在问题中指定的设计决策,但有两种方法可以解决它

更新:
orig-n
或更高版本 我应该指定我需要检查是否有一个大于或等于
orig-n
的数字。我仍然可以使用
member
功能检查这个数字,还是需要使用其他数字

您必须使用不同的东西。文档中
member
的正上方是函数(您也可以在本例中使用)。
mem
是member的缩写,
p
是“predicate”的缩写。它确定列表中的任何成员是否与某个谓词匹配

> (if (memp positive? (list -4 -2 -3 5 -1))
      "one of them is positive"
      "go fish")
"one of them is positive"
> (if (memp positive? (list -4 -2 -3 -5 -1))
      "one of them is positive"
      "go fish")
"go fish"
> (define (five-or-greater? n)
    (>= n 5))
> (if (memp five-or-greater? (list -4 -2 -3 6 -1))
      "one of them is equal to 5 or greater"
      "go fish")
"one of them is equal to 5 or greater"
> (if (memp five-or-greater? (list -4 -2 -3 4 -1))
      "one of them is equal to 5 or greater"
      "go fish")
"go fish"
要将其用于“orig-n或更高版本”,必须定义如下函数:

(define (orig-n-or-greater? n)
  (>= n orig-n))
作为主函数中的本地函数,以便它可以引用
orig-n
。然后可以像
(memp orig-n-or-more?fs)
一样使用它

汽车
功能出了什么问题?
car
函数获取列表的第一个元素,但如果列表为空,则没有第一个元素。
fs
列表开始时为空。当您尝试获取空列表的第一个元素时,会收到以下错误消息:

> (car (list))
mcar: contract violation
  expected: mpair?
  given: ()
如果列表不是空的,那么它有第一个元素,这很好:

> (car (list 4 5 6))
4
按照你在评论中的意思 然而,您的评论“检查n是否在列表中”使我相信
(equal?n(car fs))
不是您想要的。用于确定元素是否在列表中的函数被调用

因此,将
(equal?n(car fs))
测试替换为
(member n fs)
,您的代码如下所示:

; Create a list of the fibonacci sequence up to n.
(define (fib-list n)
  ; n = n, f2 = 1, f1 = 1, fs = a list.
  (let loop ((n n) (f2 1) (f1 1) (fs (list)))
    (cond
      ; If n = 0, return reversed list.
      ((zero? n) (reverse fs))
      ; Check if n is in list. If so, return list.
      ((member n fs) fs)
      ;Else, find the next fibonacci number and add it to the list.
      (else (loop (- n 1) f1 (+ f2 f1) (cons f2 fs))))))

> (fib-list 55)
(10946 6765 4181 2584 1597 987 610 377 233 144 89 55 34 21 13 8 5 3 2 1 1)
这不是你想要的答案;你想要的是
(1112355813213455)

为什么列表超过了
55
? 其中一个问题是
n
被隐藏,其方式与此表达式中的方式相同:

> (let ([n 5])
    (let ([n 10])
      n))
10
正文中的
n
指的是
10
,而不是
5

结果超过了
55
,因为循环内部
n
被阴影覆盖,变成了一个不同的数字。我猜在你关于“检查n是否在列表中”的评论中,你的意思是“检查原始n是否在列表中”。为此,你必须重命名
n
s中的一个:

> (let ([orig-n 5])
    (let ([n 10])
      orig-n))
5
在代码的上下文中:

; Create a list of the fibonacci sequence up to n.
(define (fib-list orig-n)
  ; n = n, f2 = 1, f1 = 1, fs = a list.
  (let loop ((n orig-n) (f2 1) (f1 1) (fs (list)))
    (cond
      ; If n = 0, return reversed list.
      ((zero? n) (reverse fs))
      ; Check if orig-n is in list. If so, return list.
      ((member orig-n fs) fs)
      ;Else, find the next fibonacci number and add it to the list.
      (else (loop (- n 1) f1 (+ f2 f1) (cons f2 fs))))))

> (fib-list 55)
(55 34 21 13 8 5 3 2 1 1)
颠倒 这更接近,但它是相反的。您有两个基本情况,即
(zero?n)
情况和
(member orig-n fs)
情况。在其中一个情况下,它是相反的,而在其中一个情况下,它不是。将它们都更改为调用reverse可以修复它:

; Create a list of the fibonacci sequence up to n.
(define (fib-list orig-n)
  ; n = n, f2 = 1, f1 = 1, fs = a list.
  (let loop ((n orig-n) (f2 1) (f1 1) (fs (list)))
    (cond
      ; If n = 0, return reversed list.
      ((zero? n) (reverse fs))
      ; Check if orig-n is in list. If so, return reversed list.
      ((member orig-n fs) (reverse fs))
      ;Else, find the next fibonacci number and add it to the list.
      (else (loop (- n 1) f1 (+ f2 f1) (cons f2 fs))))))

> (fib-list 55)
(1 1 2 3 5 8 13 21 34 55)
小麻木