我正在尝试在打字球拍中创建一个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-thing
和do-a-rarer-thing
在其他地方定义,并且可能具有任意参数arity和类型。因此,大约3/4的时间将调用第一个函数,而1/4的第二个函数将被调用。
但是我正在进行左右类型检查和arity问题......基于文档,我需要heterogenous rest arguments,但我不是很好地遵循文档,而不是作为一个学者类型系统...我只是希望能够指定两个函数和一个概率,并且在运行时确定调用的函数!
总的来说,可能一个宏/语法形式是一种更明智的方式来创造这种效果?从界面设计的角度来看,这个功能正是我在程序中所需要的,但我不知道如何使用静态类型实现它...但我希望静态类型能够帮助保持程序其他部分的处理。
答案 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,您将能够表达X
和Y
必须在此示例中起作用的约束。这可能是未来的工作对于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的答案更好。