簡體   English   中英

應用於 Typed Racket 中可能為空的列表

[英]Applying to potentially empty lists in Typed Racket

以下在untyped racket中是沒有問題的:

(apply hc-append
       (for/list ([colour '("red" "green" "blue")])
                 (colorize (filled-rectangle 10 10) colour)))

結果是pict包含三個不同顏色方塊的圖片。

但這在 Typed Racket 中是不可能的。 首先, for/list需要一個類型注解:

  (apply hc-append
         (for/list : (Listof pict)
                   ([colour '("red" "green" "blue")])
           (colorize (filled-rectangle 10 10) colour)))

但是, (curry apply hc-append)的類型和(for/list …)形式的結果不一致:

; […] Type Checker: Bad arguments to function in `apply':
; Domains: pict pict *
;          Real pict pict *
; Arguments:  (Listof pict)

這個錯誤信息看起來很費解,但它歸結為(Listof pict)可能是空的,並且hc-append的類型簽名需要pict pict * ,即至少一個pict

但這適用於有類型和無類型的 Racket:

(apply hc-append (map (curry colorize (filled-rectangle 10 10))
                      '("red" "green" "blue")))

(map …)表單的類型是(Pairof pict (Listof pict)) 偉大的。 那是一個非空列表。 但我不能在for/list形式中將其用作類型注釋,類型檢查器拒絕它。

即使我仔細挑選類型:

(let ([potentially-empty-list
       (for/list : (Listof pict)
                 ([c '("red" "green" "blue")])
         (colorize (filled-rectangle 10 10) c))])
  (cond
    [(null? potentially-empty-list) (blank)]
    [else (apply hc-append #{(list (first potentially-empty-list)
                                   (rest potentially-empty-list))
                             : (Pairof pict (Listof pict))})]))

我最終得到了一個非常令人困惑的消息,本質上是相同的,但現在它違背了我最初的理由,即。 該列表可能為空:類型明確指出它可能不為空! 球拍拒絕它:

; […] Type Checker: Bad arguments to function in `apply':
; Domains: pict pict *
;          Real pict pict *
; Arguments:  (List pict (Listof pict))

有兩件事讓我感到困惑:

  • 而不是我原來的(Pairof pict (Listof pict)) ,Racket 將類型變成(List pict (Listof pict)) 我覺得沒問題,因為兩者應該是等價的。
  • 如果它們是等價的,那么我希望(apply …)形式能夠工作,就像在(map …)的情況下一樣,在那里,我們也使用(apply hc-append ls) where ls has type (Pairof pict (Listof pict))

我的直覺是至少最后一個例子應該有效,但它沒有,我不明白為什么。

您的以下代碼非常接近。

(let ([potentially-empty-list
       (for/list : (Listof pict)
                 ([c '("red" "green" "blue")])
         (colorize (filled-rectangle 10 10) c))])
  (cond
    [(null? potentially-empty-list) (blank)]
    [else (apply hc-append #{(list (first potentially-empty-list)
                                   (rest potentially-empty-list))
                             : (Pairof pict (Listof pict))})]))

但是,有兩個錯誤。

  1. (list (first....) (rest...))是一個包含兩個元素的列表,其中第一個元素是一個pict ,第二個元素是一個(Listof pict) 即它有類型(List pict (Listof pict)) 我想你反而想使用(cons (first....) (rest...)) ,它有類型(Pairof pict (Listof pict) = (Listof pict)保證它至少有一個元素。
  2. 您應該改用#{(cons...):: (Pairof...)} #{x: t}表示法僅在綁定位置有效,尤其是當x是變量時。 然而, #{e:: t}表示法允許e是任意表達式,這就是您在這里所做的。 Typed Racket 在某種意義上確實存在錯誤,因為當x不是變量時它不會報告誤用#{x: t} 我會提交錯誤報告。

以下程序工作:

#lang typed/racket

(require typed/pict)

(let ([potentially-empty-list
       (for/list : (Listof pict)
         ([c '("red" "green" "blue")])
         (colorize (filled-rectangle 10 10) c))])
  (cond
    [(null? potentially-empty-list) (blank)]
    [else (apply hc-append #{(cons (first potentially-empty-list)
                                   (rest potentially-empty-list))
                             :: (Pairof pict (Listof pict))})]))

由於 Sorawee 的回答,這是我想出的一個簡化:

(: safe-apply (∀ (E R) (→ R (→ E E * R) (Listof E) R)))
(define (safe-apply def f ls)
  (cond
    [(null? ls) def]
    [else (apply f ls)]))

有趣的是,Racket 中的 Occurrence Typing 將使lscondelse子句中具有類型(Pairof E (Listof E))

然后可以這樣使用:

(safe-apply (blank)
     hc-append
     (for/list : (Listof pict)
               ([colour '("red" "green" "blue")])
       (colorize (filled-rectangle 10 10) colour)))

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM