# For/sum in typed/racket

**URL:** <https://racket.discourse.group/t/for-sum-in-typed-racket/3166>\
**Category:** Questions & Answers\
**Tags:** typed-racket\
**Created:** [September 11, 2024, 8:04pm UTC](https://racket.discourse.group/t/for-sum-in-typed-racket/3166 "2024-09-11T20:04:44Z")\
**Posts on this page:** 11\
**Page:** 1

<div class="post-metadata">

**Author:** ![ken](https://avatars.discourse-cdn.com/v4/letter/k/cc9497/32.png) [@ken](https://racket.discourse.group/u/ken)\
**Post date:** [September 11, 2024, 8:04pm UTC](https://racket.discourse.group/t/for-sum-in-typed-racket/3166/1 "2024-09-11T20:04:44Z")

</div>

I'm experimenting with typed/racket to see if it can speed up some lengthy numerical calculations. As a first step, I tried to sum all the square roots up to a million, first in plain Racket:

```scheme
(for/sum ([i 1000000])
  (sqrt i)))

```

This takes around 130ms on my computer, which isn't setting any speed records. Using `racket/flonum`, the performance is much improved:

```scheme
(for/sum ([i 1000000])
  (flsqrt (->fl i)))

```

This is down to 8ms, which is pretty good! I tried a few other languages that I know, and the only ones to beat this were C, and JS (when using floats, but not with bignums).

Next I wanted to see if typed/racket could yield similar gains, perhaps without explicit types at each step. (Ideally, it would also optimize through function calls.) Unfortunately, I've been unable to figure out a valid syntax for using `for/sum` in typed/racket.

I see lots of "type-ann-maybe" in the documentation (and are they the same in either position?), but I just can't figure out how to make the compiler happy. The documentation for this function even says "All annotations are optional", yet my first example (above) in typed/racket yields "Type Checker: Error in macro expansion -- insufficient type information to typecheck. please add more type annotations".

When I try to add annotations to help it out, such as:

```scheme
(for/sum : Flonum ([i : Integer 1000000])
  (flsqrt (->fl i)))

```

I get:

```scheme
Type Checker: type mismatch
  expected: Flonum
  given: Zero

```

I've tried every combination I can think of, of typed functions, casts, hints, and so on. No matter the error, it points to the first character of the `for/sum` line, and gives the "context" as typed-racket/typecheck/tc-toplevel.rkt, which seems unhelpful. There's nothing in the error message (at least, to this vanilla Racket user) which suggests an obvious fix.

I did see a comment somewhere (I've forgotten where) that aggregation loops are somehow special in typed/racket, perhaps due to the possibility of an empty list (even though this list can clearly never be empty), and require extra annotation, but the comment didn't actually say what to do.

Is there any tutorial which teaches how to read typed/racket error messages? Or can someone suggest a way to make `for/sum` work? I am lost here. Thanks!

---

<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:** [September 11, 2024, 8:33pm UTC](https://racket.discourse.group/t/for-sum-in-typed-racket/3166/2 "2024-09-11T20:33:48Z")

</div>

Agreed. I doubt a plain ‘client’ of Typed Racket can get this done.

The base-env file (prims.rkt) in the Typed Racket package unfortunately ‘hardwires’ `0` as a plain constant into the accumulator and that should be something that a TR programmer can specify as a base case. While `0` belongs to a number of types, it doesn’t belong to Flonum (and one could perhaps just add this).

You could fix this by modifying the file in racket/share/pkgs/typed-racket-lib/typed-racket/base-env/prims.rkt … or wait for one of the implementors to actually fix this issue.

---

<div class="post-metadata">

**Author:** ![shawnw](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/shawnw/32/1031_2.png) [@shawnw](https://racket.discourse.group/u/shawnw)\
**Post date:** [September 11, 2024, 8:54pm UTC](https://racket.discourse.group/t/for-sum-in-typed-racket/3166/3 "2024-09-11T20:54:10Z")

</div>

In this case, you can just use `for/fold` instead:

```scheme
(for/fold : Flonum
  ([sum : Flonum 0.0])
  ([i : Integer (in-range 1000000)])
  (fl+ sum (flsqrt (->fl i))))

```

---

<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:** [September 11, 2024, 9:05pm UTC](https://racket.discourse.group/t/for-sum-in-typed-racket/3166/4 "2024-09-11T21:05:20Z")

</div>

That’s what for/sum essentially expands to .. yes!

---

<div class="post-metadata">

**Author:** ![samth](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/samth/32/3_2.png) [@samth](https://racket.discourse.group/u/samth)\
**Post date:** [September 12, 2024, 3:50pm UTC](https://racket.discourse.group/t/for-sum-in-typed-racket/3166/5 "2024-09-12T15:50:45Z")

</div>

This isn't a fixable bug -- the `0` is there in the underlying `#lang racket` version and changing TR to do something different would change the semantics.

---

<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:** [September 12, 2024, 4:51pm UTC](https://racket.discourse.group/t/for-sum-in-typed-racket/3166/6 "2024-09-12T16:51:10Z")

</div>

From what I could tell TR makes the choice to put the 0 into the general typed `fold`. This means that that the TR macro could come with an option to specify the identity elements of iterators so that the type works out. (Perhaps `for/sum` is the only one.)

---

<div class="post-metadata">

**Author:** ![samth](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/samth/32/3_2.png) [@samth](https://racket.discourse.group/u/samth)\
**Post date:** [September 12, 2024, 5:05pm UTC](https://racket.discourse.group/t/for-sum-in-typed-racket/3166/7 "2024-09-12T17:05:12Z")

</div>

Typed Racket re-implements the macro (so as to propagate type annotations) but it re-implements it to have the same behavior as `for/sum` from `racket`. If `for/sum` adds something for specifying the initial value then TR will follow that.

---

<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:** [September 12, 2024, 5:19pm UTC](https://racket.discourse.group/t/for-sum-in-typed-racket/3166/8 "2024-09-12T17:19:01Z")

</div>

Thanks for reminding me of my design guideline 🙂

(I have experimented with `for/max` and `for/min` which would need such neutral elements too. When I recover from Sw Dev, I may take a stab at that.)

---

<div class="post-metadata">

**Author:** ![ken](https://avatars.discourse-cdn.com/v4/letter/k/cc9497/32.png) [@ken](https://racket.discourse.group/u/ken)\
**Post date:** [September 14, 2024, 10:33pm UTC](https://racket.discourse.group/t/for-sum-in-typed-racket/3166/9 "2024-09-14T22:33:31Z")

</div>

Thanks! Both for the sample code, and letting me know I'm not crazy for missing an obvious `for/sum` solution.

Perhaps it would be worthwhile to make a note in the documentation that `for/sum` doesn't (and can't) match Racket semantics perfectly, like for flonums, and/or what to use instead? I see I'm not the first person to struggle with this.

Anyway, this typed/racket `for/fold` solution is longer (and less obvious), needs explicit type annotations, still requires `racket/flonum` wrapper functions, and the result here is 5x slower than standard Racket. So I think typed/racket is not the solution for me in this case.

---

<div class="post-metadata">

**Author:** ![samth](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/samth/32/3_2.png) [@samth](https://racket.discourse.group/u/samth)\
**Post date:** [September 17, 2024, 3:03pm UTC](https://racket.discourse.group/t/for-sum-in-typed-racket/3166/10 "2024-09-17T15:03:32Z")

</div>

1. `for/sum` in Typed Racket does match Racket's semantics.
2. When I time the following programs:

```scheme
#lang typed/racket
(require racket/flonum)
(time
 (for/fold : Flonum
   ([sum : Flonum 0.0])
   ([i : Integer (in-range 1000000)])
   (fl+ sum (flsqrt (->fl i)))))

```

and

```scheme
#lang racket
(time
 (for/sum ([i (in-range 1000000)])
   (sqrt i))

```

and

```scheme
#lang racket
(require racket/flonum)
(time
 (for/sum ([i (in-range 1000000)])
   (flsqrt (->fl i)))

```

The TR program is about twice as fast as the Racket program using `flsqrt` and 25x faster than the Racket program with just `sqrt`.

---

<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:** [September 17, 2024, 6:40pm UTC](https://racket.discourse.group/t/for-sum-in-typed-racket/3166/11 "2024-09-17T18:40:25Z")

</div>

> [@samth](#):
>
> 1. `for/sum` in Typed Racket does match Racket's semantics.

Just to be very explicit, the differences between

> [@samth](#):
>
> ```scheme
> #lang typed/racket
> (require racket/flonum)
> (time
> (for/fold : Flonum
> ([sum : Flonum 0.0])
> ([i : Integer (in-range 1000000)])
> (fl+ sum (flsqrt (->fl i)))))
> 
> ```

and the semantics of `for/sum` are:

1. The `sum` variable is initially `0`, which is not a `Flonum`; and
2. Therefore, the results have to be combined with `+`, not `fl+`.

> [@ken](#):
>
> Unfortunately, I've been unable to figure out a valid syntax for using `for/sum` in typed/racket.
> 
> …
> 
> When I try to add annotations to help it out, such as:
> 
> ```scheme
> (for/sum : Flonum ([i : Integer 1000000])
> (flsqrt (->fl i)))
> 
> ```
> 
> I get:
> 
> ```scheme
> Type Checker: type mismatch
> expected: Flonum
> given: Zero
> 
> ```

The issue here is that you have annotated the result of `for/sum` as a `Flonum`, but the typechecker can't prove that the sequence is non-empty (that would need dependent types), so it can't prove that the result won't be `0`.

Here is a working version:

```scheme
#lang typed/racket
(require racket/flonum)
(for/sum : (U Zero Flonum) ([i 1000000])
  (flsqrt (->fl i)))

```

If you need to use the result as a `Flonum`, `assert` will do that with a minimum of runtime cost:

```scheme
#lang typed/racket
(require racket/flonum)
(fl+ 1.0
     (assert (for/sum : (U Zero Flonum) ([i 1000000])
               (flsqrt (->fl i)))
             flonum?))

```

The `assert` expands to something like `(if (flonum? x) x (error "not a Flonum"))`. While writing `(cast x Flonum)` would also work, `cast` in Typed Racket uses the contract system, which has a greater runtime cost: `assert` is generally preferable when its first-order check is sufficient.

> [@ken](#):
>
> ```scheme
> Type Checker: type mismatch
> expected: Flonum
> given: Zero
> 
> ```
> 
> I've tried every combination I can think of, of typed functions, casts, hints, and so on. No matter the error, it points to the first character of the `for/sum` line, and gives the "context" as typed-racket/typecheck/tc-toplevel.rkt, which seems unhelpful. There's nothing in the error message (at least, to this vanilla Racket user) which suggests an obvious fix.

I agree that this is a very confusing error message. I'm not familiar with the right parts of the Typed Racket implementation to know how to produce a better message, but it might mean an adjustment around here:

> <https://github.com/racket/typed-racket/blob/eabda9300739cd93c74bc0cf2ed4c9f3bfe631eb/typed-racket-lib/typed-racket/base-env/prims.rkt#L523-L534>
