简介
嗨,我是Racket的新手,也是功能语言的新手,因此我很难做到简单的事情(特别是当互联网上没有太多的资料时)
实际问题:
我开始编写一个函数,给出列表的最大值和最小值。因此,该函数接收2个变量,一个是列表,第二个是一个列表,其中最多只保留2个变量和最小值。 然后当" list"为null表示我查看了列表中的所有变量。这意味着我想"返回" maxMin列表,但当然功能语言不会这样工作。
怎么做?
以下是我想要实现的目标:
#lang pl
(define (maxMin list maxiMini)
(if (null? list)
;return the max and min from list when finished looking at the list
(maxiMini)
; else do other things
)
)
答案 0 :(得分:3)
您要找的是continuation。 (作为旁注,使用Racket的exception handling系统也可以在这里工作。如果您可以在此处重写代码以使用with-handlers
而不是let/ec
,则可以获得奖励积分。)
虽然延续的大部分用途都非常强大,但这种特殊模式是相当标准的,而IMO对它们来说是少数很好的用途之一。基本上,延续就像C语言中的控制流语句(break
,continue
,return
,goto
,yield
等),除了这些语言,那些控制流语句是关键字,在Racket中,continuation是一等值。
这意味着你可以在技术上返回另一个函数return语句,并且在调用它时,代码会在第一次返回时返回到大致其状态。因此,您可以制作生成器模式。如果你不小心的话,你可以看到它如何变得非常复杂。
然而,如果你不想回归' (可以这么说)延续,你可以使用更简单(和更轻的重量)逃脱延续。这些工作与C中的setjump
和longjmp
非常相似。您可以使用它们从内部上下文返回,但如果控制流离开了转义延续的范围,则堆栈不能重建。 (基本上,转义延续可以弹出堆栈帧,但它们无法恢复类似的常规延续。)
Racket有一个很好的形式来创建转义延续let/ec
,它创建一个转义延续。调用时,整个表达式求值为转义延续的值。例如,以下函数通常会计算为4
:
(define (looper)
3
4)
> (looper)
4
但是如果我们插入一个转义延续(让我们称之为return
),它会从函数中提前返回,从而导致它被评估为3:
(define (looper2)
(let/ec return
(return 3)
4))
> (looper2)
3
您可以看到如何将其嵌入到您希望提前返回的大型函数中:
(define (large-function)
(let/ec return
... lots of code ...
(when some-condition
(return some-value))
... lots of code ...))
当然,大多数时候你想要像这样早点回归,因为它有一些特殊的状态,这就是为什么我强烈建议你只使用Racket的异常处理系统。您可以使用raise
抛出异常,并使用with-handlers
捕获一个异常。
答案 1 :(得分:2)
这是一个返回一些东西的函数:
(define (min a b)
(if (< a b)
a
b))
这将“返回”if
的结果。 if
“根据a
”返回的内容返回“b
或(< a b)
的评估”。
我在引号中写“返回”,因为在lisp langauges中通常会说“表达式求值为”。想象一下:
(min 5 10)
上面的表达式求值为5 ..如果要将结果放在另一个表达式中:
(+ (min 5 10) 1)
然后(min 5 10)
评估为5
,这是+
与1
一起应用的第一个值6
,然后评估为<
。
另请注意,变量 (< 4 5)
会对某个函数求值,因此尝试像a
一样调用它,但是b
和(a)
是数字,不能像a
那样调用。它不会起作用。如果您熟悉algol语言,则与变量a()
相同,这是一个数字,并使用它--output-fzn-to-stdout
。