Typed Racket convert Any to All(a)

时间:2017-12-20 02:11:54

标签: functional-programming scheme racket typed-racket typed

我正在尝试在take的输出上调用flatten。问题是take需要a列表,但flatten会返回Any列表。有没有办法在它们之间进行转换?或者其他一些我应该采取的方法?我无法在Racket Docs中找到任何示例。

(: extend (All (a) (-> (Listof a) Integer (Listof a))))               
(define (extend l n)                                 
  ; extend a list to length 'n' by appending it to itself           
  ;                                                        
  ; @l        list of any                                         
  ; @n        int                                              
  ; @return   list of any 

  (take (flatten (make-list n l)) n)) 

从解释器中,以下是每个函数的确切类型以供参考。

 > take                
 - : (All (a) (-> (Listof a) Integer (Listof a)))       
 #<procedure:take> 

 > flatten             
 - : (-> Any (Listof Any))
 #<procedure:flatten>

以下是错误消息供参考。

alg/waterfall.rkt:65:2: Type Checker: Polymorphic function `take' could not be applied to arguments:                                                                         
Argument 1:                                                                 
  Expected: (Listof a)                                                      
  Given:    (Listof Any)                                                    
Argument 2:                                                                 
  Expected: Integer                                                         
  Given:    Integer                                                         

Result type:     (Listof a)                                                 
Expected result: (Listof a)  

1 个答案:

答案 0 :(得分:1)

@Alexis King是对的。 flatten函数具有更复杂的行为,不适合您需要的类型。 append*函数更简单,这里实际上是您需要的而不是flatten

在您使用它的地方:

; n : Integer
; l : (Listof a)
(take (flatten (make-list n l)) n)
; expected type: (Listof a)

flatten的输入是(Listof (Listof a)),要进行类型检查,输出必须是(Listof a)。即使a包含列表* ,也必须如此 *。

您想要的功能是(Listof (Listof a)) -> (Listof a)类型的功能。现在,flatten总是有这种类型吗?不,它不能,这是一个反例:

a = (Listof Integer)
input : (Listof (Listof (Listof Integer)))
input = (list (list (list 1)))
expected output type: (Listof (Listof Integer))
actual output value:  (list 1)

因此flatten不能使用(Listof (Listof a)) -> (Listof a)类型。你需要的是append*,它有这种类型。

> append*
- : (All (a) (-> (Listof (Listof a)) (Listof a)))
#<procedure:append*>

在您的示例中,您可以使用append*使用flatten

(: extend (All (a) (-> (Listof a) Integer (Listof a))))               
(define (extend l n)                                 
  ; extend a list to length 'n' by appending it to itself           
  ;                                                        
  ; @l        list of any                                         
  ; @n        int                                              
  ; @return   list of any 

  (take (append* (make-list n l)) n))