Re: SRFI 284: define-typed Artyom Bologov 24 Sep 2026 21:10 UTC

Hi y’all, hi Arne,

Here are my chaotic comments on SRFI 284:

> If you don’t want to name the procedure, adding types may not be
> useful.

I see your point here, but I find that typed lambdas are sometimes
useful in conveying their purpose. Say, if you’re iterating over a hash
table serialized from opaque JSON, which is basically string -> number.
You likely don’t want to make a new function just for that, but you
still want to make your intent clear even there. So something like that:

(hash-table-walk
 (lambda ([name string?] [rating real?])
   (display (string-append "Rating of tripleS " name " was "
                           (number->string rating) " photocard points.\n")))
 fan-elections)

Additional benefit of such code is that malformed JSON (say, with null
rating) will inevitably raise type errors.

Another argument here would be: we name lambda arguments (some better,
some worse,) despite these functions almost always being
throwaway. Because we do care about what goes there. So why not include
types too?

However, I respect your decision and am not going to force you into
neither including nor eliding lambda-typed in SRFI 284. But I had to
braindump on that, because I really like SRFI 253 lambda-checked!

> It works well together with the checks for data defined in SRFI 253
> and SRFI 273.

It would be nice if the document linked to respective SRFI documents
when mentioning them. It’s the cheapest way to ensure the reader is not
lost in all these opaque integers. I mean, SRFI-2X3 is pretty much my
trademark now, but these are still unclear.

On a related note: can you add IDs to the document sections so that
hypertext people like me can link to the respective sections for
reference purposes?

> Different from define-checked in SRFI 253, define-typed does not
> interleave types with arguments, but provides them as second list
> after the arguments. This keeps the procedure arguments easier to
> grasp at a glance as long as they all fit on a single line […]

I have settled on a mix of parens and square brackets for checked
procedures, as seen in the above lambda-checked and in this:

(define-checked (read-x-if [block-start list?] [p port?])
  #| ... |#)

This is _slightly_ non-portable, but reads much easier.

> The argument types and the return type are separated by ->.

May I suggest => instead? It’s already used for threading cond / case
and SRFI 273 return type checks, so it makes sense to re-use it instead
of adding new auxiliary syntax.

However, I also see the point on familiarity and I have to agree that ->
is clear enough. So use your judgment.

> The form define-typed* supports named and optional arguments, while
> define-typed only supports positional arguments, because supporting
> named and optional arguments incurs a cost in runtime and
> implementation complexity.

I’d also have inserted a note on non-portability of named / optional /
keyword argument here. Highlighting the safe standard status of
define-typed is beneficial I think.

Also, it’s a bummer that rest arguments are not supported. These are
quite useful and prevalent!

> The implementation for Guile is as fast as manually added type guards
> at the start of the body as described in the article Optimizing Guile
> Scheme. This makes define-typed an easier way to speed up hot inner
> loops, as long as the predicates give the compiler the needed
> information.

I could’ve been snarky and suggested that we collaborate on improving
define-checked that’s already in Guile 😜 But I don’t want to do that,
because your work is important and useful too!

In particular, I see aesthetic value in define-typed, because you’re
reasonable in claiming that types separated from names might be more
readable. I don’t necessarily agree with that, but I program in C, so my
opinion can be safely discarded here 🤣

> The return types can be either a single predicate for a single value,
> for example string?, a form with multiple predicates for multiple
> values, one per value, for example (string? string?), or a form with a
> single predicate that receives all return values as list, for example
> (all-string?).

This is dangerous. What if I wanted to use something like

(cut memq <> '(input output input-output))

as my return type check? Would be recognized as multiple value checks
instead of a single value check, purely because it contains parentheses?
SRFI 253 / 273 avoid that ambiguity by always requiring
parentheses. Much like standard let and cond requiring them. Sure, it’s
ugly and inconvenient at times. But at least it won’t break in horrible
ways.

On a related note: the format of argument checks in not fully specified
as far as I can see. Can you specify these too?

Another note: maybe write out the full grammar of these in the document?
It’s fun to reverse-engineer behaviors from syntax-rules, at least for
me—but not for everyone I think.

All in all, this is all useful work, so thanks for using SRFI process to
gather feedback on it. The document is a pleasurable read too!

Best of love,
--
Artyom Bologov
https://aartaka.me