简体   繁体   English

在 Typed Racket 中转换为任意类型折叠树

[英]Casting to arbitrary type in Typed Racket folding a Tree

I'm trying to produce a typed Racket procedure that for some type A , takes a Tree , and a function from two A s to an A , another parameter of type A , and returns a value of type A .我正在尝试生成一个类型化的 Racket 过程,对于某些类型A ,它需要一个Tree和一个 function 从两个A到一个A ,另一个A类型的参数,并返回一个A类型的值。 I'm not very familiar with the (All) syntax, but I tried using it.我对(All)语法不是很熟悉,但我尝试使用它。 Unfortunately, my code produces the following error message at build-time:不幸的是,我的代码在构建时产生以下错误消息:

Type Checker: Polymorphic function `foldr' could not be applied to arguments:
Types: (-> a b b) b (Listof a)  -> b
       (-> a b c c) c (Listof a) (Listof b)  -> c
       (-> a b c d d) d (Listof a) (Listof b) (Listof c)  -> d
Arguments: (-> A A A) A (Listof Any)
Expected result: A

My code:我的代码:

(: fold : (All (A) (Instance Tree) (A A -> A) A -> A))
(define (fold tree f base)
  (foldr
    f
    base
    (cons
      (value tree)
      (map 
        (lambda
          ([tree : (Instance Tree)])
          (fold tree f base)
          ) 
        (children tree)
        )
      )
    )
  )

I tried to simplify the function until it started to work, and this was where it started working:我试图简化 function 直到它开始工作,这就是它开始工作的地方:

(: fold : (All (A) (Instance Tree) (A A -> A) A -> A))
(define (fold tree f base)
  (foldr f base (list base))
)

I think what's happening is that the type checker doesn't know that (value tree) is also of type A .我认为正在发生的事情是类型检查器不知道(value tree)也是A类型。 Is there any way I can (Cast) it to be of type A ?有什么办法可以(Cast)它是A型? If not, how would I approach getting this to work?如果没有,我将如何让这个工作?

Without the definition of the Tree type it's hard to answer this question.如果没有Tree类型的定义,就很难回答这个问题。 But the answer in general is not to cast, but to have a type which is a tree of nodes which are of some type.但一般来说,答案不是强制转换,而是拥有一种类型,即具有某种类型节点树。 I don't understand classes in Racket, least of all their interaction with typed Racket (which seems to be all subject to change), but here is how you do that with struct s, which are well-supported in typed Racket:我不了解 Racket 中的类,尤其是它们与类型化 Racket 的交互(这似乎都可能发生变化),但这是你如何使用struct来做到这一点的,它在类型化 Racket 中得到了很好的支持:

(struct (A) tree
  ((value : A)
   (children : (Listof (Treeof A))))
  #:type-name Treeof)

And now I can check this:现在我可以检查一下:

> (tree 1 (list (tree -1 '())))
- : (Treeof (U Negative-Fixnum One))
#<tree>
> (tree 1 (list (tree 'x '())))
- : (Treeof (U 'x One))
#<tree>

OK, the types its working out are a little unhelpful, but they're correct.好的,它的工作类型有点无用,但它们是正确的。

Once you've done this, then it knows nice things about tree-value and tree-children :完成此操作后,它就会知道有关tree-valuetree-children

> tree-value
- : (All (A) (-> (Treeof A) A))
#<procedure:tree-value>
> tree-children
- : (All (A) (-> (Treeof A) (Listof (Treeof A))))
#<procedure:tree-children>

And that's enough to write your function (I'm not sure it is correct, but its types now makes sense):这足以编写您的 function (我不确定它是否正确,但它的类型现在有意义):

(: fold-tree (All (A) (-> (Treeof A) (-> A A A) A A)))
(define (fold-tree tree f base)
  (foldr f base
         (cons
          (tree-value tree)
          ;; I don't know why it needs this since it knows about tree-children
          (map (λ ((child : (Treeof A)))
                 (fold-tree child f base))
               (tree-children tree)))))

Note that for some reason it can't work out that child in (map (λ (child)...) (tree-children tree)) is a (Treeof A) even though it knows that tree is and it knows what tree-children does.请注意,由于某种原因,它无法计算出(map (λ (child)...) (tree-children tree)) child的孩子是(Treeof A)即使它知道tree是并且它知道是什么tree-children会。 So I had to tell it that (an older version was buggy and used tree instead of child , which concealed this problem.所以我不得不告诉它(旧版本有问题并且使用tree而不是child ,这隐藏了这个问题。

With the struct type definition as in the answer by tfb ,使用tfb答案中的结构类型定义,

#lang typed/racket

(struct (A) tree
  ((value : A)
   (children : (Listof (Treeof A))))
  #:type-name Treeof)

the following definition works (somewhat):以下定义有效(有点):

(: fold-tree (All (A R) (-> (Treeof A) (-> A R R) R R)))
(define (fold-tree tree f base)
  (f (tree-value tree)
     (foldr
          (lambda ((child : (Treeof A)) (r : R))
            (fold-tree child f r))
          base
          (tree-children tree))))

Now trying it in the interactions window,现在在交互 window 中尝试它,

(fold-tree (tree 1 (list (tree 2 '()))) + 0)

works and returns工作并返回

- : Integer [more precisely: Nonnegative-Integer]
3

but trying the seemingly equivalent但尝试看似等价的

(fold-tree (tree 1 (list (tree 2 '()))) (lambda (a r) (+ a r)) 0)

brings up a lot of errors.带来很多错误。

update: thanks to tfb's input, the following calls all work:更新:感谢 tfb 的输入,以下调用均有效:

> (fold-tree (tree 1 (list (tree 2 '()))) (lambda ((a : Number) (r : Number)) (+ a r)) 0)
- : Number
3

> (fold-tree (tree 1 (list (tree 2 '()))) (lambda ((a : Any) (b : Any)) (cons a b)) 0)
- : (U Zero (Pairof Any Any))
'(1 2 . 0)

> (fold-tree (tree 1 (list (tree 2 '()))) (lambda ((a : Any) (b : Any)) (cons a b)) '())
- : (U Null (Pairof Any Any))
'(1 2)

> (fold-tree (tree 1 (list (tree 2 '()))) (lambda ((a : Any) (b : (Listof Any)))
     (cons a b)) '())
- : (Listof Any)
'(1 2)

> (fold-tree (tree 1 (list (tree 2 '()))) (lambda ((a : Number) (b : (Listof Number))) 
     (cons a b)) '())
- : (Listof Number)
'(1 2)

> (fold-tree (tree 1 (list (tree 2 '()))) (lambda (a b) (cons a b)) '())
- : (U Null (Pairof Any Any))
'(1 2)

> (fold-tree (tree 1 (list (tree 2 '()))) cons '())
*** Type Checker: Polymorphic function `fold-tree' could not be applied to arguments:
Argument 1:
  Expected: (Treeof A)
  Given:    (Treeof Positive-Byte)
Argument 2:
  Expected: (-> A R R)
  Given:    (All (a b) (case-> (-> a (Listof a) (Listof a)) (-> a b (Pairof a b))))
Argument 3:
  Expected: R
  Given:    Null
 in: (fold-tree (tree 1 (list (tree 2 (quote ())))) cons (quote ()))
> 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM