`apply` `set-union` in Typed Racket

Hello,

I am trying to apply set-union to a list in Typed Racket. The following happily works and gives the expected answer:

#lang typed/racket

(apply set-union (list (set 'a 'b) (set 'c 'd)))

However, if I bind the list to a variable with an explicit Listof type, I get the following:

(define lst : (Listof (Setof Symbol))
  (list (set 'a 'b) (set 'c 'd)))
(apply set-union lst)
; tmp.rkt:8:0: Type Checker: Bad arguments to function in `apply':
; Domains: (Listof e) (Listof e) *
;          (Setof e) (Setof e) *
; Arguments:  (Listof (Setof Symbol))
; 
;   in: (apply set-union lst)

Explicitly instantiating the type of apply doesn't help:

(apply (inst set-union (Setof Symbol)) lst)
; tmp.rkt:10:0: Type Checker: Bad arguments to function in `apply':
; Domains: (Listof (Setof Symbol)) (Listof (Setof Symbol)) *
;          (Setof (Setof Symbol)) (Setof (Setof Symbol)) *
; Arguments:  (Listof (Setof Symbol))
; 
;   in: (apply (inst set-union (Setof Symbol)) lst)

I suspected that apply works for (list (set 'a 'b) (set 'c 'd)) because the type of the latter is inferred as (List ...), so things break when I force it to (Listof ...), but the following works:

(define lst1 : (Listof Number) '(1 2 3))
(apply + lst1)

Is there a way to apply set-union to a Listof sets?

1 Like

The error message already suggests the problem: set-union requires at least one argument, that is, the list must be nonempty. To communicate this information with the type checker, you’ll need to use a type like (Pairof (Setof Symbol) (Listof (Setof Symbol))). To do this more conveniently, you can define a type constructor:

#lang typed/racket
(define-type (NonEmptyListof A) (Pairof A (Listof A)))

(: lst (NonEmptyListof (Setof Symbol)))
(define lst (list (set 'a 'b) (set 'c 'd)))

(apply set-union lst)
4 Likes

Oooh, thank you @usao , this seems so obvious now that you have explained it to me!

The error message was indeed quite explicit, but I didn't read (Setof e) (Setof e) * properly.