如何在类型球拍中创建“概率”HOF(或语法)

时间:2014-03-21 21:52:35

标签: types scheme racket typed-racket

我正在尝试在打字球拍中创建一个HOF,这将允许我表达这个想法,“在评估时,滚动骰子并选择要应用的程序”。

目前,我正在使用以下内容:

(: odds-on ((Any * -> Any) (Any * -> Any) Real -> (Any * -> Any)))
(define (odds-on choice alternative odds)
  (cond [(< (random) odds) choice]
    [else alternative]))

有了这个想法,我可以像这样使用它:

> ((odds-on do-a-common-thing do-a-rarer-thing .75) 'x '(a b c) (set z))

其中do-a-common-thingdo-a-rarer-thing在其他地方定义,并且可能具有任意参数arity和类型。因此,大约3/4的时间将调用第一个函数,而1/4的第二个函数将被调用。

但是我正在进行左右类型检查和arity问题......基于文档,我需要heterogenous rest arguments,但我不是很好地遵循文档,而不是作为一个学者类型系统...我只是希望能够指定两个函数和一个概率,并且在运行时确定调用的函数!

总的来说,可能一个宏/语法形式是一种更明智的方式来创造这种效果?从界面设计的角度来看,这个功能正是我在程序中所需要的,但我不知道如何使用静态类型实现它...但我希望静态类型能够帮助保持程序其他部分的处理。

2 个答案:

答案 0 :(得分:4)

让我为您的示例提出一个更简单的(在某些方面)类型:

(: odds-on (All (X Y) (X Y Real -> (U X Y))))
(define (odds-on choice alternative odds) 
  (cond [(< (random) odds) choice]
        [else alternative]))

并像这样使用它:

-> ((odds-on (lambda () (displayln "hi"))
             (lambda () (displayln "bye"))
             0.75))
bye
-> ((odds-on (lambda ([x : String]) (string-append x "1"))
             (lambda ([x : String]) (string-append x "2"))
             0.23)
    "test")
- : String
"test2"

虽然这里有一点权衡,因为现在你可以传递odds-on实际上不起作用的东西。如果您碰巧传递odds-on一些非函数值,您将无法调用返回的值(即,类型检查器无论如何都会在以后捕获它)。

(注意:另外,如果Typed Racket支持bounded polymorphism,您将能够表达XY必须在此示例中起作用的约束。这可能是未来的工作对于TR。)

返回类型中还有(U X Y),你必须要小心。如果使用不兼容的参数arities传递odds-on两个函数,则调用结果函数将更加困难。

-> ((odds-on (lambda () (displayln "hi"))
             (lambda (x) (displayln "bye"))
             0.75))
; readline-input:10:0: Type Checker: could not apply function;
;  wrong number of arguments provided
;   expected: 1
;   given: 0
;   in: ((odds-on (lambda () (displayln "hi")) (lambda (x) (displayln "bye"))
;     0.75))
; [,bt for context]

(注意:您的错误消息可能看起来不一样。我正在运行Racket v6.0.0.4。此外,此错误消息并不是那么好。)

答案 1 :(得分:1)

我还是Typed Racket的新手,所以我不认为这是一个很好的答案。

类型(Any * -> Any)用于同源休息参数。所以函数需要实际采取休息参数,例如(define (f . xs) ...)(lambda xs ...)。如果我相应地改变你的例子,它会为我打字:

#lang typed/racket

(: odds-on ((Any * -> Any) (Any * -> Any) Real -> (Any * -> Any)))
(define (odds-on choice alternative odds)
  (cond [(< (random) odds) choice]
        [else alternative]))

((odds-on (lambda xs (second xs)) ;; <--
          (lambda xs (third xs))  ;; <--
          0.75)
 'x 'y 'z)

当然,您可能不希望函数采用xs之类的休息参数而不是像x y z这样的普通参数。您可能只是在尝试查找将要键入check的某事时使用rest参数。在那种情况下,我还不知道该告诉你什么。


更新:根据您的评论,我使用Procedure类型对此进行了另一次破解,但事实并非如此。

#lang typed/racket

(: odds-on (Procedure Procedure Real -> Procedure))
(define (odds-on choice alternative odds)
  (cond [(< (random) odds) choice]
        [else alternative]))

(define x (odds-on (lambda () #t)
                   (lambda () #f)
                   0.75))

x
; - : Procedure
; #<procedure:/tmp/tr.rkt:9:10>

(x)
; stdin::12271: Type Checker: Cannot apply expression of type Procedure, since it is not a function type
;   in: (x)

一方面,x 一个Procedure。另一方面,x无法应用,因为它 a Procedure。而在第三方面,我很困惑。

更新:这不起作用的原因是Procedure是一种&#34;不透明的&#34;类型,这意味着,&#34;这件事满足procedure?,但我们不知道更多 - 因此不知道如何安全地调用它#34;。这就是错误信息的禅宗,&#34;程序不是函数类型&#34;的意义,实际上确实有意义。

Asumu的答案更好。