# Question about unconstrained-domain-\> in the Racket guide

**URL:** <https://racket.discourse.group/t/question-about-unconstrained-domain-in-the-racket-guide/3786>\
**Category:** Questions & Answers\
**Tags:** question, contract\
**Created:** [June 11, 2025, 1:04am UTC](https://racket.discourse.group/t/question-about-unconstrained-domain-in-the-racket-guide/3786 "2025-06-11T01:04:38Z")\
**Posts on this page:** 11\
**Page:** 1

<div class="post-metadata">

**Author:** ![chiroptical](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/chiroptical/32/2313_2.png) [@chiroptical](https://racket.discourse.group/u/chiroptical)\
**Post date:** [June 11, 2025, 1:04am UTC](https://racket.discourse.group/t/question-about-unconstrained-domain-in-the-racket-guide/3786/1 "2025-06-11T01:04:38Z")

</div>

Hey! I am currently working my way through the Racket guide and I am struggling a bit to grok `unconstrained-domain->` in the example [7.3&nbsp;Contracts on Functions in General](https://docs.racket-lang.org/guide/contracts-general-functions.html#(part._contracts-no-domain)).

I'll paste the example here and work through my understanding thus far and hopefully someone can help fill in the gaps.

```racket
(define (n-step proc inits)
  (let ([inc (apply proc inits)])
    (when inc
      (n-step proc (map (λ (x) (+ x inc)) inits)))))

(provide (contract-out [n-step
                        (->i ([proc
                               (inits)
                               (and/c (unconstrained-domain-> (or/c #f number?))
                                      (λ (f) (procedure-arity-includes? f (length inits))))]
                              [inits (listof number?)])
                             ()
                             any)]))

```

I want to export `n-step` with this contract. We use the `->i` to handle optional parameters, we have none so this could be `->`? Or, do I need `->i` to enable this syntactic form? `proc` is the first parameter of the function and I don't quite understand the `(inits)` syntax that follows it. Is this stating that `proc` takes a single argument `inits`? It can't (right?) otherwise we wouldn't need to check the arity matches the length of inits. Everything beyond that makes sense.

I took this example and attempted to write a contract with ` unconstrained-domain->` for the following stupid example,

```racket
(define (increment x)
  (+ x 1))

(provide (contract-out [increment
                        (->i ([x (and/c (unconstrained-domain-> number?) (λ (y) (> y 2)))]) () any)]))

```

i.e. increment will only work for numbers greater than 2. I understand this is silly, but I wanted to test my understanding. I guess ideally it would also check that `y` is a `number?`. The error I get from this is,

```scheme
> (increment 1)
increment: contract violation
  expected: a procedure
  given: 1
  in: the 1st conjunct of
      the x argument of
      (->i
       ((x
         (and/c
          (unconstrained-domain-> number?)
          ...-guide/chapter7.rkt:237:73)))
       any)
  contract from: 
      /home/chiroptical/programming/racket/the-racket-guide/chapter7.rkt
  blaming: top-level
   (assuming the contract is correct)
  at: /home/chiroptical/programming/racket/the-racket-guide/chapter7.rkt:236:24
 [,bt for context]

```

It is entirely possible my syntax is just wrong.

---

<div class="post-metadata">

**Author:** ![chiroptical](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/chiroptical/32/2313_2.png) [@chiroptical](https://racket.discourse.group/u/chiroptical)\
**Post date:** [June 11, 2025, 1:48am UTC](https://racket.discourse.group/t/question-about-unconstrained-domain-in-the-racket-guide/3786/2 "2025-06-11T01:48:34Z")

</div>

> [@chiroptical](#):
>
> It can't (right?) otherwise we wouldn't need to check the arity matches the length of inits

I guess it can! The point is we are passing a list of arguments to the function proc and applying them.

---

<div class="post-metadata">

**Author:** ![EmEf](https://avatars.discourse-cdn.com/v4/letter/e/53a042/32.png) [@EmEf](https://racket.discourse.group/u/EmEf)\
**Post date:** [June 11, 2025, 2:59am UTC](https://racket.discourse.group/t/question-about-unconstrained-domain-in-the-racket-guide/3786/3 "2025-06-11T02:59:11Z")

</div>

`->i` is a _dependent_ contract, meaning it can describe a dependency among the arguments to a function and its result(s).

In this example, the contract for the first arguments `proc` depends on the (length of the) second argument `inits`.  
For historical reasons, the `->i` form demands that a programmer must specify this dependency explicitly.

By contrast, the second argument does not depend on the value of anything else, so there’s no such “dependency clause.”

The `and/c` contract for `proc` states two constraints:

— (1) it is a procedure that can take any kind of value and any number  
— (2) it is a procedure that must be able to take as many arguments as `inits` contains elements.

So the second part of the `and/c` refines the first one.

;; - - -

```scheme
define (increment x) (+ x 1))

```

This function must consume a number, because its body says it increments the number by 1.

But, your contract says that its one and only argument must be a procedure _and_ that this procedure  
should be greater than 2 — which of course will always fail because a procredure can’t be compared to  
a number.

The contract that you describe in English would look like this:

```scheme
(provide
(contract-out
(increment
;; increments numbers greater than 2 by 1
(-> (lambda (y) (> y 2)) any/c)))

```

(This is my preferred format of specifying exports.)

---

<div class="post-metadata">

**Author:** ![LiberalArtist](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/liberalartist/32/151_2.png) [@LiberalArtist](https://racket.discourse.group/u/LiberalArtist)\
**Post date:** [June 11, 2025, 3:26am UTC](https://racket.discourse.group/t/question-about-unconstrained-domain-in-the-racket-guide/3786/4 "2025-06-11T03:26:17Z")

</div>

> [@chiroptical](#):
>
> We use the `->i` to handle optional parameters, we have none so this could be `->`? Or, do I need `->i` to enable this syntactic form? `proc` is the first parameter of the function and I don't quite understand the `(inits)` syntax that follows it.

The complicated parts of this example have more to do with `->i` than with `unconstrained-domain->`.

While `->i` is capable of handling optional arguments, the reason to use the `->i` combinator (instead of `->*` or in this case, as you say, `->`) is because you want one of the sub-contracts to depend on the actual value of one of the arguments when the function is called. This is introduced in [§ 7.3.6 Argument and Result Dependencies](https://docs.racket-lang.org/guide/contracts-general-functions.html#%28part._contracts-arrow-d%29).

For comparison, let's consider a non-dependent contract that you might write for `n-step`:

```scheme
(provide (contract-out
          [n-step
           (-> (unconstrained-domain-> (or/c #f number?))
               (listof number?)
               any)]))

```

This contract says that `n-step` takes two arguments:

1. A procedure that returns `(or/c #f number?)`; and
2. A list of numbers.

In particular, using `unconstrained-domain->` means the contract doesn't say anything about what kinds of arguments the procedure passed to `n-step` takes.

That's all correct! But there is an additional requirement you might want to check: that the procedure argument actually accepts the number of arguments that are given in the `(listof number?)` argument.

Let's take a closer look at `->i`, with the sub-expressions replaced by emoji so we can focus on the syntax of `->i` itself.

```scheme
(->i ([proc
       (inits)
       🍎]
      [inits 🍏])
     ()
     any)

```

Both the `[proc (inits) 🍎]` clause and the `[inits 🍏]` clause are what [the full documentation for `->i`](https://docs.racket-lang.org/reference/function-contracts.html#%28form._%28%28lib._racket%2Fcontract%2Fbase..rkt%29._-~3ei%29%29) calls _mandatory-dependent-dom_[ain] clauses, which means they are about required arguments to `n-step`. In `[proc (inits) 🍎]`, the `(inits)` part means that the 🍎 expression depends on the actual value of the `inits` argument at runtime. When `n-step` is called, the contract will first check that the second argument satisfies the contract produced by the 🍏 expression. Then, the contract will evaluate the 🍎 expression with `inits` bound to the actual value of the second argument, after checking. So, in the actual 🍎 expression:

```scheme
(and/c (unconstrained-domain-> (or/c #f number?))
       (procedure-arity-includes/c (length inits)))

```

the reference to `inits` refers to the binding established by the `(inits)` part of `[proc (inits) 🍎]`.

---

<div class="post-metadata">

**Author:** ![chiroptical](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/chiroptical/32/2313_2.png) [@chiroptical](https://racket.discourse.group/u/chiroptical)\
**Post date:** [June 11, 2025, 11:51am UTC](https://racket.discourse.group/t/question-about-unconstrained-domain-in-the-racket-guide/3786/5 "2025-06-11T11:51:17Z")

</div>

> [@LiberalArtist](#):
>
> Both the `[proc (inits) 🍎]` clause and the `[inits 🍏]` clause are what [the full documentation for `->i`](https://docs.racket-lang.org/reference/function-contracts.html#%28form._%28%28lib._racket%2Fcontract%2Fbase..rkt%29._-~3ei%29%29) calls _mandatory-dependent-dom_[ain] clauses, which means they are about required arguments to `n-step`. In `[proc (inits) 🍎]`, the `(inits)` part means that the 🍎 expression depends on the actual value of the `inits` argument at runtime. When `n-step` is called, the contract will first check that the second argument satisfies the contract produced by the 🍏 expression

This is so immensely helpful. Thank you!

---

<div class="post-metadata">

**Author:** ![chiroptical](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/chiroptical/32/2313_2.png) [@chiroptical](https://racket.discourse.group/u/chiroptical)\
**Post date:** [June 11, 2025, 11:53am UTC](https://racket.discourse.group/t/question-about-unconstrained-domain-in-the-racket-guide/3786/6 "2025-06-11T11:53:08Z")

</div>

> [@EmEf](#):
>
> The contract that you describe in English would look like this:

_Can_ the contract for `increment` be written with `unconstrained-domain->` even if it is weird? (going to try a bit more this morning with my new information)

---

<div class="post-metadata">

**Author:** ![chiroptical](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/chiroptical/32/2313_2.png) [@chiroptical](https://racket.discourse.group/u/chiroptical)\
**Post date:** [June 11, 2025, 12:02pm UTC](https://racket.discourse.group/t/question-about-unconstrained-domain-in-the-racket-guide/3786/7 "2025-06-11T12:02:08Z")

</div>

> [@LiberalArtist](#):
>
> `unconstrained-domain->`

Ahh, okay, I am reading [8.2&nbsp;Function Contracts](https://docs.racket-lang.org/reference/function-contracts.html#%28form._%28%28lib._racket%2Fcontract%2Fbase..rkt%29._unconstrained-domain-~3e%29%29) and I see my confusion. It is designed to work for functions.

It was pointed out here,

> [@EmEf](#):
>
> But, your contract says that its one and only argument must be a procedure _and_ that this procedure

but I missed the connection.

---

<div class="post-metadata">

**Author:** ![chiroptical](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/chiroptical/32/2313_2.png) [@chiroptical](https://racket.discourse.group/u/chiroptical)\
**Post date:** [June 11, 2025, 12:04pm UTC](https://racket.discourse.group/t/question-about-unconstrained-domain-in-the-racket-guide/3786/8 "2025-06-11T12:04:29Z")

</div>

Thank you both! I understand this a lot better now.

---

<div class="post-metadata">

**Author:** ![chiroptical](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/chiroptical/32/2313_2.png) [@chiroptical](https://racket.discourse.group/u/chiroptical)\
**Post date:** [June 11, 2025, 12:22pm UTC](https://racket.discourse.group/t/question-about-unconstrained-domain-in-the-racket-guide/3786/9 "2025-06-11T12:22:23Z")

</div>

I guess this is illustrative? The `f` takes two arguments and outputs a number. The output of `increase` must be greater than the sum of `x` and `y`.

```racket
(define (increase f x y)
  (f x y))

(provide (contract-out
          [increase
           (->i ([f (and/c (unconstrained-domain-> number?) (λ (f) (procedure-arity-includes? f 2)))]
                 [x number?]
                 [y number?])
                ()
                (lambda (x y) (>/c (+ x y))))]))

(increase (lambda (x y) (* 2 x y)) 1 2) ; would work

(increase (lambda (x y) (* x y)) 1 2) ; wouldn't work

```

---

<div class="post-metadata">

**Author:** ![chiroptical](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/chiroptical/32/2313_2.png) [@chiroptical](https://racket.discourse.group/u/chiroptical)\
**Post date:** [June 11, 2025, 12:26pm UTC](https://racket.discourse.group/t/question-about-unconstrained-domain-in-the-racket-guide/3786/10 "2025-06-11T12:26:49Z")

</div>

Obviously, you could write `f` more directly because if `x` and `y` are `number?` than `f` must be `(-> number? number? number?)` but I'm learning.

---

<div class="post-metadata">

**Author:** ![LiberalArtist](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/liberalartist/32/151_2.png) [@LiberalArtist](https://racket.discourse.group/u/LiberalArtist)\
**Post date:** [June 16, 2025, 7:58pm UTC](https://racket.discourse.group/t/question-about-unconstrained-domain-in-the-racket-guide/3786/11 "2025-06-16T19:58:52Z")

</div>

Comparing `(-> number? number? number?)` and

```scheme
(and/c (unconstrained-domain-> number?)
       (procedure-arity-includes/c 2))

```

both contracts check that:

- The procedure must produce a single result, which must satisfy `number?`; and that
- The procedure must accept two arguments.

However, the key difference is that second contract _does not_ check that the arguments to the function satisfy `number?`.

The same thing is true of the contract in the Guide for the `proc` argument to `n-step`. Here's an alternate contract for the `proc` argument to `n-step` that does check the arguments:

```scheme
(->i ([proc (inits)
            (dynamic->* #:mandatory-domain-contracts (make-list (length inits) number?)
                        #:range-contracts (list (or/c #f number?)))]
      [inits (listof number?)])
     any)

```

The main message of [§ 7.3.9 Fixed but Statically Unknown Arities](https://docs.racket-lang.org/guide/contracts-general-functions.html#(part._contracts-no-domain)) is that the techniques from [§ 7.3.2 Rest Arguments](https://docs.racket-lang.org/guide/contracts-general-functions.html#%28part._contracts-rest-args%29) don't solve the problem, because those contracts say "that the function must accept _any_ number of arguments, not a _specific_ but _undetermined_ number".

The suggestion of `unconstrained-domain->` (it seems a bit misleading that the Guide calls it "the correct contract") is one tool that can solve the problem; `dynamic->*` is another. You could write a dependent contract or leave the arity unchecked: how precise to make a contract is always a pragmatic decision.

* * *

It might be helpful to know that the name `unconstrained-domain->` comes from the terminology of mathematical functions, which use "domain" and "range" for what programmers more often call a functions "arguments" and "results".
