# For/first, for\*/first, for/and, for\*/and, for/last in Typed Racket

**URL:** https://racket.discourse.group/t/for-first-for-first-for-and-for-and-for-last-in-typed-racket/1002
**Category:** Questions & Answers
**Tags:** typed-racket
**Created:** [May 16, 2022, 10:59pm UTC](https://racket.discourse.group/t/for-first-for-first-for-and-for-and-for-last-in-typed-racket/1002 "2022-05-16T22:59:50Z")
**Posts on this page:** 4
**Page:** 1

<div class="post-metadata">

### Author: ![scolobb](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/scolobb/32/108_2.png) [@scolobb](https://racket.discourse.group/u/scolobb)
#### Post date: [May 16, 2022, 10:59pm UTC](https://racket.discourse.group/t/for-first-for-first-for-and-for-and-for-last-in-typed-racket/1002/1 "2022-05-16T22:59:50Z")

</div>

Hi,

I tried using `for/first` in Typed Racket in many different ways, in particular like this:

```scheme
(for/first : Integer ([i : Integer '(1 2 3)]) (ann i Integer))

```

As you can see, I put in all type annotations I could think of, but I still get:

```scheme
Type Checker: Error in macro expansion -- insufficient type information to typecheck. please add more type annotations

```

Then, I accidentally saw in the Typed Racket reference that `for/first`, `for*/first`, `for/and`, and `for*/and` are not supported: [2&nbsp;Special Form Reference](https://docs.racket-lang.org/ts-reference/special-forms.html#%28form._%28%28lib._typed-racket%2Fbase-env%2Fprims..rkt%29._for%2Fand%29%29).

I was somewhat surprised, given that the same chapter of the reference says that `for/last` is supported for example. So I tried

```scheme
(for/last ([i '(1 2 3)]) i)

```

which gave me

```scheme
; /gnu/store/nhcp7rxxlkvxc4gw20v87gs65isi3xzq-racket-vm-cs-8.5/opt/racket-vm/collects/racket/private/for.rkt:2095:6: Type Checker: type mismatch
; expected: False
; given: Integer
; in: result

```

Oh. The following works by the way:

```scheme
(for/last ([i '(1 2 3)]) #f)

```

but it is obviously kind of useless.

Is there a deep reason for these family of macros to be broken/unsupported? I haven't yet checked their Typed Racket definitions, but I would be happy to help fixing them is somebody is available to provide guidance.

FWIW, I can get the behavior of `for/first` with the following slightly more verbose `for/fold`, which typechecks fine:

```scheme
(for/fold ([res : (U False Integer) #f])
          ([i '(1 2 3)])
  #:break (not (eq? res #f))
  i)

```

---

<div class="post-metadata">

### Author: ![NoahStoryM](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/noahstorym/32/17_2.png) [@NoahStoryM](https://racket.discourse.group/u/NoahStoryM)
#### Post date: [May 17, 2022, 12:40am UTC](https://racket.discourse.group/t/for-first-for-first-for-and-for-and-for-last-in-typed-racket/1002/2 "2022-05-17T00:40:08Z")

</div>

The return type of `for/last` should be of `Option` type.

```scheme
> (for/last ([i '()]) : Any (error 'e))
- : Any
#f
> (for/last ([i '(1 2 3)]) : (Option Integer) i)
- : (U False Integer)
3

```

I guess the `for/and` and `for/first` issues might be related to how they are expanded in untyped version.

```scheme
(define-for-variants (for/and for*/and)
  ([result #t])
  (lambda (x) x)
  (lambda (rhs) #`(stop-after #,rhs (lambda x (not result))))
  (lambda (x) x))

(define-for-variants (for/or for*/or)
  ([result #f])
  (lambda (x) x)
  (lambda (rhs) #`(stop-after #,rhs (lambda x result)))
  (lambda (x) x))

(define-for-variants (for/first for*/first)
  ([val #f] [stop? #f])
  (lambda (x) #`(let-values ([(val _) #,x]) val))
  (lambda (rhs) #`(stop-after #,rhs (lambda x stop?)))
  (lambda (x) #`(values #,x #t)))

(define-for-variants (for/last for*/last)
  ([result #f])
  (lambda (x) x)
  (lambda (rhs) rhs)
  (lambda (x) x))

```

---

<div class="post-metadata">

### Author: ![scolobb](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/scolobb/32/108_2.png) [@scolobb](https://racket.discourse.group/u/scolobb)
#### Post date: [May 17, 2022, 11:04pm UTC](https://racket.discourse.group/t/for-first-for-first-for-and-for-and-for-last-in-typed-racket/1002/3 "2022-05-17T23:04:08Z")

</div>

> [@NoahStoryM](#):
>
> The return type of `for/last` should be of `Option` type.

Woow, OK, thanks! That's not obvious at all. Perhaps I should submit a PR to say that explicitly in the docs.

> [@NoahStoryM](#):
>
> I guess the `for/and` and `for/first` issues might be related to how they are expanded in untyped version.

Interesting hypothesis, but I am under the impression that Typed Racket actually redefines `for/last` as a variation of `for/fold`:

- definition of `for/last`: [https://github.com/racket/typed-racket/blob/70c21b4addd8c3c1deda1b37410fd8b13f6cae9b/typed-racket-lib/typed-racket/base-env/prims.rkt#L548](https://github.com/racket/typed-racket/blob/70c21b4addd8c3c1deda1b37410fd8b13f6cae9b/typed-racket-lib/typed-racket/base-env/prims.rkt#L548)
- definition of `define-for/acc:-variants`: [https://github.com/racket/typed-racket/blob/70c21b4addd8c3c1deda1b37410fd8b13f6cae9b/typed-racket-lib/typed-racket/base-env/prims.rkt#L539](https://github.com/racket/typed-racket/blob/70c21b4addd8c3c1deda1b37410fd8b13f6cae9b/typed-racket-lib/typed-racket/base-env/prims.rkt#L539)
- definitino of `define-for/acc:-variant`: [https://github.com/racket/typed-racket/blob/70c21b4addd8c3c1deda1b37410fd8b13f6cae9b/typed-racket-lib/typed-racket/base-env/prims.rkt#L510](https://github.com/racket/typed-racket/blob/70c21b4addd8c3c1deda1b37410fd8b13f6cae9b/typed-racket-lib/typed-racket/base-env/prims.rkt#L510)

Well, after some squinting at the code, I am not that sure about my impression at all any more 😃

Where I agree with you is that the untyped expansions of `for/first` and `for/last` are quite different, the latter one being simpler. On the other hand, I have just tried

```scheme
(for/and ([i '(#f #t)]) : Boolean i)

```

and it worked nicely, despite the comment in the docs and in the source. I wonder whether the fact that `for/first` is not supported is a remnant of some previous version of Typed Racket, especially given that it seems quite easy to implement in terms of `for/fold`, which does typecheck.

I'll investigate more and report back.

---

<div class="post-metadata">

### Author: ![scolobb](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/scolobb/32/108_2.png) [@scolobb](https://racket.discourse.group/u/scolobb)
#### Post date: [July 1, 2022, 11:36pm UTC](https://racket.discourse.group/t/for-first-for-first-for-and-for-and-for-last-in-typed-racket/1002/4 "2022-07-01T23:36:14Z")

</div>

OK, _ages_ and tons of day-job-things-done later, here is a summary of my advances.

I implemented myself the following simple versions of `for/first` and `for*/first`:

```scheme
(define-for-syntax (make-for/first/typed-variant folder)
  (syntax-parser
    #:literals (:)
    [(_ :
        ty:expr ; These should probably be more specific.
        clauses:expr
        c ...)
     #`(#,folder : ty
        ([result : ty #f])
        clauses
        #:break (not (equal? result #f))
        c ...)]))

(define-syntax for/first/typed (make-for/first/typed-variant 'for/fold))
(define-syntax for*/first/typed (make-for/first/typed-variant 'for*/fold))

```

This code is in fact in [this repository](https://git.marvid.fr/scolobb/dds/src/branch/master/utils.rkt#L32), and is perfectly sufficient for my current purposes.

Typical usage:

```scheme
> (for/first/typed : (Option Integer) ([i (list 1 2 3)]) i)
- : (U False Integer)
1

```

* * *

I read quite carefully the definition of [`define-for/acc:-variant`](https://github.com/racket/typed-racket/blob/70c21b4addd8c3c1deda1b37410fd8b13f6cae9b/typed-racket-lib/typed-racket/base-env/prims.rkt#L510) and it seems to me quite easy to extend it to include the simple `#:break` when the accumulator becomes different from `#f`. This is what I suggest in [this PR](https://github.com/racket/typed-racket/pull/1252), but I don't believe my implementation actually works (I still have trouble building Typed Racket properly from a Git repository (I am on Guix System)). Therefore, my best hope is that this PR can be transformed into something different and better 😉
