The Racket Guide阅读笔记,chapter 20, 21,22, 23.

20 Parallelism

Racket提供两种形式的并行,future以及place。

Racket的thread只为并发使用,不为并行使用。

future的功能通过racket/future库来实现。

20.1 Parallelism with Futures

例子:

#lang racket

(define (any-double? l)
  (for/or ([i (in-list l)])
    (for/or ([i2 (in-list l)])
      (= i2 (* 2 i)))))


(define l1 (for/list ([i (in-range 5000)])
             (+ (* 2 i) 1)))
(define l2 (for/list ([i (in-range 5000)])
             (- (* 2 i) 1)))

(let ([f (future (lambda () (any-double? l2)))])
  (or (any-double? l1)
      (touch f)))

上述的f同步执行(any-double? l2)

future-visualizer可以用来剖析future:

(require future-visualizer)
(visualize-futures
 (let ([f (future (lambda () (mandelbrot 10000000 62 501 1000)))])
   (list (mandelbrot 10000000 62 500 1000)
         (touch f))))

future-unsafe操作可分为两类:future的计算被阻塞;显示进行同步。

20.2 Parallelism with Places

racket/place提供不同的raket运行实例间的通信。不同的place之间必须使用消息传递来通信,比如place-channel-put以及place-channel-get。

下面是一个例子:

(define (main)
  (define p
    (place ch
      (define l (place-channel-get ch))
      (define l-double? (any-double? l))
      (place-channel-put ch l-double?)))
 
  (place-channel-put p (list 1 2 4 8))
 
  (place-channel-get p))

(place ch …)的内容会在一个新的place执行,而且可以通过ch来与原进程通信。

上面的代码保存成double.rkt之后可以通过racket -tm double.rkt来执行。-tm表示执行模块中的main函数。

place形式还有两个微妙的特性。首先place的正体部分会升格成一个匿名的,模块级别的函数,这意味着place正体部分所引用的符合必须在模块的顶层。其次,place形式会通过dynamic-require来在新的place导入当前模块,这意味着不要在顶层直接或者间接调用place,会造成死循环:

#lang racket
 
(provide main)
 
; Don't do this!
(define p (place ch (place-channel-get ch)))
 
(define (indirect-place-invocation)
  (define p2 (place ch (place-channel-get ch))))
 
; Don't do this, either!
(indirect-place-invocation)

20.3 Distributed Places

racket/place/distributed提供了分布式编程。

21 Running and Creating Executables

21.1 Running racket and gracket

gracket和racket类似,不过以GUI程序出现。根据传入的参数不同,racket或者gracket可以运行:

  • interactive mode
  • module mode
  • load mode

21.1.1 Interactive Mode

默认情况下,调用racket直接进入REPL模式。此模式下,racket会先请求racket/init模块,并且会加载(find-system-path 'init-file)中的文件。

如果在命令行求值racket -e '(display "hi\n")',可以在其之后使用-i选项停留在交互模式。

可以使用-l来加载一个模块,从而跳过racket/initracket -l racket/base -i。这个例子中如果将-l-i互换,那么会在加载racket/base之前加载racket/init

21.1.2 Module Mode

如果单给racket提供一个文件:racket hello.rkt,那么这个文件会被当成一个模块加载。这个后面可以跟其他选项,不过选项会被放置在current-command-line-arguments之内。

可以通过-u-t来加载模块的时候指定其相应的命令行。区别是对于后者,额外的命令行有racket处理,而不是直接传给模块本身。

-l-t类似,不过是从库中加载。racket -l raco等同于raco。此格式下,如果要传参数给raco,需要指定在--之后,如racket -l raco -- --help

21.1.3 Load Mode

使用-f或者--load标记可以直接从文件加载顶层表达式,而不是把文件当成一个模块。效果就像是在REPL中直接输入表达式一样,只不过不会打印结果,例子:

racket -f hi.rkts

也可以直接用-e来指定在REPL中执行的表达式:

  racket -e '(current-seconds)'

和交互模式相同,上述操作会请求racket/init。同样地,可以指定-l来修改默认请求的模块:

racket -l racket/base -e '(current-seconds)'

21.2 Scripts

21.2.1 Unix Scripts

21.2.2 Windows Batch Files

竟然可以这样:

 ; @echo off

  ; Racket.exe "%~f0" %*

  ; exit /b

  #lang racket/base

  "Hello, world!"

21.3 Creating Stand-Alone Executables

参考raco的文档。

22 More Libraries

只涉及在The racket reference中记录的语言和库。

22.1 Graphics and GUIs

  • racket/draw,画图相关,可以画位图以及PostScript
  • racket/gui,图形界面相关
  • pict,基于racket/draw,可以用于Slideshow或者Scribble。
  • 2htdp/image,和上一条类似,不过更适合于教学
  • sgl,提供OpenGL支持。

22.2 The Web Server

22.3 Using Foreign Libraries

22.4 And More

https://pkgs.racket-lang.org提供更多程序包。

23 Dialects of Racket and Scheme

racket并不只是支持racket。

23.1 More Rackets

Racket发行版中自带的一众语言

  • typed/racket,静态类型
  • lazy,惰性求值
  • frtime,支持反应式编程
  • scribble/base,更像是Latex的语言,用于写文档

23.2 Standards

R5RS没有指定模块系统。但是对于单个的R5RS文件,可以使用#lang r5rs让其在racket中运行。

R6RS给定义了一个模块系统。R6RS可以在文件头执行#!r6rs,racket会将其等同于#lang r6rs

23.3 Teaching

略。

(完)