Skip to content

[DRY?] Direct definition vs. generic combinators, ctd. in Algebra.Definitions.RawMonoid #2475

Open
@jamesmckinna

Description

@jamesmckinna

Addition: suggest adding to Data.Vec.Functional.Base

-- Non-empty folds

foldr₁ : (A  A  A)  Vector A (suc n)  A
foldr₁ {n = zero}  _⊕_ xs = head xs
foldr₁ {n = suc _} _⊕_ xs = (head xs) ⊕ foldr₁ _⊕_ (tail xs)

foldl₁ : (A  A  A)  Vector A (suc n)  A
foldl₁ _⊕_ xs = foldl _⊕_ (head xs) (tail xs)

(and perhaps also retrofitting to Data.Vec.Base, too)

Refactoring: suggest replacing the definitions in Algebra.Definitions.RawMonoid with

sumʳ sumˡ sum :  {n}  Vector Carrier n  Carrier

sumʳ {n = zero}  xs = 0#
sumʳ {n = suc _} xs = Vector.foldr₁ _+_ xs

sumˡ {n = zero}  xs = 0#
sumˡ {n = suc _} xs = Vector.foldl₁ _+_ xs

sum = Vector.foldr _+_ 0#

(with the last one for backwards compatibility; but even for right-associative addition, sumʳ avoids redundancy in the {n = 1} case)
and then also

_×_ : Carrier  Carrier
n × x = sum (Vector.replicate n x)

_×′_ : Carrier  Carrier
n ×′ x = sumˡ (Vector.replicate n x)

(again: using sumʳ in the first definition might be an improvement? although a breaking change...)

BUT as to performance/intensional reduction behaviour:

  • it seems that replacing the existing direct definitions of _×_ and _×′_ in this way, even with {-# INLINE ... #-} directives, just doesn't quite give the correct unfolding behaviour for the existing proofs in Algebra.Properties.Monoid.Mult.* to go through properly;
  • is there some way to achieve this? (eg by more inlining? if so, how/when do we decide what's appropriate; stdlib seems to be quite sparing in its appeals to such 'extralogical' techniques)
  • would such a change actually be more efficient in practice than the existing direct definitions?

It seems as though the 'generic' definitions ought to be more robust/reusable/'better' (esp. as Vector.replicate is simply const, so the use of head and tail in the various folds is inlinable/eliminable?), but it just ... doesn't quite seem to work :-(

Any help/insight into how to (understand how to) resolve this trade-off welcome! It feels as though I am missing something fundamental, but possibly non-obvious, about what's going on here.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions