Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Spine-lazy vector functions #2808

Open
gergoerdi opened this issue Sep 8, 2024 · 1 comment
Open

Spine-lazy vector functions #2808

gergoerdi opened this issue Sep 8, 2024 · 1 comment

Comments

@gergoerdi
Copy link
Contributor

Functions that construct vectors with a known length should be able to produce the spine fully lazily. For example, I don't think there's a good reason why map (const 0) (undefined :: Vec 5 ()) should bottom out.

So I propose rewriting the vector functions a la the following examples:

map :: forall n a b. (KnownNat n) => (a -> b) -> Vec n a -> Vec n b
map f = go (toUNat SNat)
  where
    go :: forall n. UNat n -> Vec n a -> Vec n b
    go UZero     ~Nil       = Nil
    go (USucc n) ~(x :> xs) = f x :> go n xs

zipWith :: forall n a b c. (KnownNat n) => (a -> b -> c) -> Vec n a -> Vec n b -> Vec n c
zipWith f = go (toUNat SNat)
  where
    go :: forall n. UNat n -> Vec n a -> Vec n b -> Vec n c
    go UZero     ~Nil       ~Nil       = Nil
    go (USucc n) ~(x :> xs) ~(y :> ys) = f x y :> go n xs ys

(I'm including zipWith here to demonstrate how nicely unbiased it becomes with this technique).

@gergoerdi
Copy link
Contributor Author

As @kleinreact can attest to, I have real-life code where, due to zipWith being unnecessarily lazy in its first argument's spine, f <$> x <*> y loops, whereas pure f <*> x <*> y works, which can be hella confusing unless one is aware of zipWith's details.

# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant