美文网首页
Racket函数二三事

Racket函数二三事

作者: XGLey | 来源:发表于2018-03-04 22:08 被阅读0次

前言

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

调用

(+ 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
>

相关文章

  • Racket函数二三事

    前言 我们离不开函数,到哪里都有它的身影。 调用 +是个函数,它可以接受两个、三个或者更多的参数。random也是...

  • 4.6本地绑定

    racket提供三个函数执行本地绑定 let , let* , letrec . 4.6.1平行绑定:let le...

  • 下载,安装,运行,关闭racket

    (下载 racket) 打开racket-lang.org,在这里你可以下载到racket。包含了Drracket...

  • [Racket] Language Model(二):Synta

    The syntax of a Racket program is defined by Racket 程序的语法是...

  • [Racket] racket模块

    DrRacket分为上下两块,上面的称为definitions area,下面的称为interactions ar...

  • fact,Y组合子,currying

    lang racket ;阶乘函数最初版本 ;调用很正常 ;调用方式为(fact-i2 6 1)result必须传...

  • Racket指南

    racket指南面向有编程经验的racket新手。章节2提供了racket概要介绍。从章节3开始,该指南深入细节,...

  • 6.1模块基础

    每个Racket模块都存在自己的文件。 其它模块可以引入cake.rkt来使用print-cake函数,因为pro...

  • The Little Schemer-CHP1

    在 Windows 下配置环境 在 http://racket-lang.org/ 下载 Racket 并安装 运...

  • 2019-08-11 Mac安装Racket并加入环境变量

    安装Racket Racket是一种通用编程语言,也是世界上第一个面向语言编程的生态系统。 Racket下载的地址...

网友评论

      本文标题:Racket函数二三事

      本文链接:https://www.haomeiwen.com/subject/ljwqfftx.html