Reputation: 1
I'm trying to type annotate the following function in typed/racket.
(define (add . vals)
(apply map (lambda (x y) (+ x y)) vals))
Since add is a variable arity function, I've given the input type as Any *. As the map function returns a list of results, it could have type (Listof Any). So I tried annotating it with (: add (-> Any * (Listof Any))
.
However, the typechecker fails on the function body with error:
stacker.rkt:26:2: Type Checker: Bad arguments to function in `apply':
Domains: (-> a b ... b c) (Listof a) (Listof b) ... b
(-> a c) (Pairof a (Listof a))
Arguments: (case-> (-> Nonnegative-Fixnum Nonpositive-Fixnum Fixnum) (-> Nonpositive-Fixnum Nonnegative-Fixnum Fixnum) (-> Index Index Nonnegative-Fixnum) (-> Zero Number Number) (-> Number Zero Number)) (Listof Any)
in: (apply map (lambda (x y) (+ x y)) vals)
It's a rather confusing error message to decode and any help with reasoning about this would be much appreciated.
(Update: the above question was actually me trying to simplify the original problem I had. Not the best idea, but the initial discussion did help my make some progress, but I still have some issues.)
The functions I'm trying to type annotate are as follows:
(: string->datum : String -> Any)
(define (string->datum s)
(read (open-input-string (format "(~a)" s))))
(: format-datum : Datum String * -> Any)
(define (format-datum datumTemplate . vals)
(string->datum (apply format (format "~a" datumTemplate) vals)))
(: format-datums : Datum (Listof String) * -> (Listof Any))
(define (format-datums datumTemplate . valsLst)
(apply map (lambda v (apply format-datum datumTemplate v)) valsLst))
(displayln (format-datum '(handle ~a) "yyy"))
(displayln (format-datums '(handle ~a) '("yyy" "zzz")))
(displayln (format-datums '(handle ~a ~a) '("yyy" "zzz") '("xxx" "mmm")))
Essentially I was working through the stacker example in Beautiful Racket (https://beautifulracket.com/stacker/intro.html) and was trying to implement some of the helper functions in the "br" language myself.
One of the helper functions is to take the datum obtained from reading a file and replacing them with a new datum that follows a template, in this case '(handle ~a) for every line in the source file.
format-datum and format-single both type check and run fine, but format-datums doesn't pass the type checker and I'm unsure exactly what I'm doing incorrectly (as again the untyped version works fine).
The type checker calls the error :
Bad arguments to function in `apply':
Domains: (-> a b ... b c) (Listof a) (Listof b) ... b
(-> a c) (Pairof a (Listof a))
Arguments: (-> Any * Nothing) (Listof (Listof String))
Update: I just figured it out I think. Realised I wasn't passing the list argument to the map in the previous version, which is what you were doing in the add example. So changed it to the following and it type checks.
(: format-datums : Datum (Listof String) (Listof String) * -> (Listof Any))
(define (format-datums datumTemplate v1 . valsLst)
(apply map (lambda [v : String *] (apply format-datum datumTemplate v)) v1 valsLst))
Out of curiosity, if you could have partial function application in Racket, would you be able to write the same function without consuming the initial list as v1 but rather partially applying just the lambda to map and then passing valsLst to it?
Upvotes: 0
Views: 67
Reputation: 52579
Like Sorawee mentioned in a comment, this signature doesn't make any sense for your code. The use of the lambda constrains it to exactly two arguments, both of which should be lists of Number
, Real
, Integer
, Float
, etc. to satisfy +
's type. And since there's only two arguments, why use apply
? Here's a fixed version, and one that takes one or more lists to compare that does use apply
:
(: add : (Listof Number) (Listof Number) -> (Listof Number))
(define (add l1 l2)
(map + l1 l2))
(: add-many : (Listof Number) (Listof Number) * -> (Listof Number))
(define (add-many l1 . lists)
(apply map + l1 lists))
and some example usage:
Language: typed/racket/base, with debugging; memory limit: 128 MB.
> (add '(1 2 3) '(4 5 6))
- : (Listof Number)
'(5 7 9)
> (add-many '(1 2 3) '(4 5 6) '(7 8 9))
- : (Listof Number)
'(12 15 18)
Upvotes: 0