Racket函数二三事

前言

我们离不开函数,到哪里都有它的身影。

调用

(+ 1 2) ;; 3
(+ 1 2 3) ;; 6
(random) ;; 0.123122

+是个函数,它可以接受两个、三个或者更多的参数。random也是个函数,它并没有接受任何参数,直接返回一值。

匿名函数

匿名函数也是函数,它跟普通函数区别在于它没有名字,与它相对的称为具名函数。我们一般用lambdaλ表示,如下:

(map (lambda (x) (string-append x "!")) "hello!")
(map (λ (x) (string-append x "!") "hello!")

以上两种写法相同。

简写

变量的绑定(定义):

(define var 1)

函数也是个变量,所以我们可以这样写:

(define my-fun
    (lambda (x y) (+ x x y y)))

我们将一个匿名函数绑定到my-fun上,于是它变成一个函数,同样地,我们可以使用以下简写:

(define (my-fun x y)
    (+ x x y y))

它们在此时(函数参数固定)可以认为等价,它们之间还是会有细微不同,下面将一一介绍。

不定个数参数

记法

比较以下两种写法:

(define (f/id x) x)
(define l/id (lambda x x))

按照上一节的写法,它们所表达含义应该是相一致。我们测试几个例子:

> (f/id 1)
1
> (f/id '(1 2))
'(1 2)p
> (f/id 1 2)
; f/id: arity mismatch;
;  the expected number of arguments does not match the given number
;   expected: 1
;   given: 2
;   arguments...:
;    1
;    2
(l/id 1)
'(1)
> (l/id '(1 2))
'((1 2))
> (l/id 1 2)
'(1 2)

f/idl/id基本相同,但在处理多个输入值出现了问题,f/id默认会检查参数个数,而lambda却不会这样做。

如果我们想要定义自己的+,直接使用lambda

(define my-add
    (lambda xs (foldl + 0 xs)))

(my-add 1 2 3) ;; 6

剩余参数

racket可以匹配多个参数,如果例如我们实现自己的head

(define my-head
    (lambda (x . xs) xs))

(define (my-head x . xs) xs)

以上写法就会相等价,同样地,我们还可以把前面多个参数一起匹配出来。

(define (my-headdd a b c . xs) xs)

.后面就是剩余下来未处理的参数,它是一个list,利用这一点,我们也可以实现my-add

(define (my-add x . xs)
    (foldl + 0 (cons x xs)))

我们把xxs再拼回到一个list,之后一齐处理。

参数关键词

racket函数提供关键词用法,让整个函数更加可读。
与不定参数一样,我们同样有两种写法。

(define my-add (lambda (z #:x x #:y y) (+ x y z)))

(define (my-add z #:x x #:y y) (+ x y z))

z是个普通参数,xy需要特殊方法输入:

(my-add 10 #:x 1 #:y 2) ;; 13

默认参数

不管是不定参数还是关键词,它们都可以提供一个默认值。

一组默认参数,需要用方括号包围起来。

(define (my-add [x 1] [y 1]) (+ x y))

(my-add)
2
> (my-add 2)
3
> (my-add 10 20)
30
>
(define (my-add z #:x [x 1] #:y [y 1]) (+ x y z))

(my-add 10)
12
> (my-add 10 #:x 20)
31
> (my-add 10 #:x 10 #:y 10)
30
>

Apply

在不定参数中我们用foldl来实现加法运算。+本身已经实现了多参数相加,但我们的函数得到的是一个list,为了能把这些参数列表运用(apply)到+,我们就可以使用apply来处理了。

(define my-add
    (lambda xs (apply + xs)))

约束

racket/contract提供了函数的约束能力,能严格限制一个函数的输入输出,例如我们想让my-add仅支持自然数,那么我们可以这样写:

(define/contract (my-add x y)
    (-> positive? positive? positive?)
    (+ x y))

(my-add 0 1)
; my-add: contract violation
;   expected: positive?
;   given: 0
;   in: the 1st argument of
;       (-> positive? positive? positive?)
;   contract from: (function my-add)
;   blaming: top-level
;    (assuming the contract is correct)
;   at: stdin::1411-1417
>

->算作是约束记法。

不定参数约束

我们扩展my-add,可以让它接受多个参数,并且要求它每个参数都为自然数。

(define/contract my-add
    (->* () () #:rest (listof positive?) positive?)
    (lambda xs (apply + xs)))

(my-add 1 2)
3
> (my-add 1 2 10)
13
> (my-add 1 2 0)
; my-add: contract violation
;   expected: positive?
;   given: 0
;   in: an element of
;       the rest argument of
;       (->* () #:rest (listof positive?) positive?)
;   contract from: (definition my-add)
;   blaming: top-level
;    (assuming the contract is correct)
;   at: stdin::1731-1737
>

我们逐个分析->*后面的三个参数。

  • ()my-add必须接受的参数,此处我们并没有要求必须参数个数,所以置空。
  • () #:rest (listof positive?),此处就是对剩余参数的约束。
  • positive?,返回值约束。

我们同样可以简单改写:

(define/contract (my-add x . xs)
    (->* (positive?) () #:rest (listof positive?) positive?)
    (apply + (cons x xs)))

关键词

关键词的约束与普通函数写法并不多,也用#:keyword表示出来即可。

(define/contract (my-add z #:x x #:y y)
    (-> positive? #:x positive? #:y positive? positive?)
    (+ x y z))
> (my-add 1 #:x 1 #:y 1)
3
> (my-add 0 #:x 1 #:y 1)
; my-add: contract violation
;   expected: positive?
;   given: 0
;   in: the 1st argument of
;       (->
;        positive?
;        #:x
;        positive?
;        #:y
;        positive?
;        positive?)
;   contract from: (function my-add)
;   blaming: top-level
;    (assuming the contract is correct)
;   at: stdin::1884-1890
> (my-add 1 #:x 0 #:y 1)
; my-add: contract violation
;   expected: positive?
;   given: 0
;   in: the #:x argument of
;       (->
;        positive?
;        #:x
;        positive?
;        #:y
;        positive?
;        positive?)
;   contract from: (function my-add)
;   blaming: top-level
;    (assuming the contract is correct)
;   at: stdin::1884-1890
>

默认参数

默认参数的约束跟不定参数一样,需要用到->*。以我们在“默认参数”定义的my-add为例。

(define/contract (my-add x [y 1] #:z [z 1])
    (->* (positive?)
         (positive?
          #:z positive?)
         positive?)
    (+ x y z))
> (my-add 1)
3
> (my-add 0)
; my-add: contract violation
;   expected: positive?
;   given: 0
;   in: the 1st argument of
;       (->*
;        (positive?)
;        (positive? #:z positive?)
;        positive?)
;   contract from: (function my-add)
;   blaming: top-level
;    (assuming the contract is correct)
;   at: stdin::2071-2077
> (my-add 1 0)
; my-add: contract violation
;   expected: positive?
;   given: 0
;   in: the 2nd argument of
;       (->*
;        (positive?)
;        (positive? #:z positive?)
;        positive?)
;   contract from: (function my-add)
;   blaming: top-level
;    (assuming the contract is correct)
;   at: stdin::2071-2077
> (my-add 1 1 #:z 0)
; my-add: contract violation
;   expected: positive?
;   given: 0
;   in: the #:z argument of
;       (->*
;        (positive?)
;        (positive? #:z positive?)
;        positive?)
;   contract from: (function my-add)
;   blaming: top-level
;    (assuming the contract is correct)
;   at: stdin::2071-2077
>
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,718评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,683评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,207评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,755评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,862评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,050评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,136评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,882评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,330评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,651评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,789评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,477评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,135评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,864评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,099评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,598评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,697评论 2 351

推荐阅读更多精彩内容