morloc icon indicating copy to clipboard operation
morloc copied to clipboard

Cannot force order of operations

Open arendsee opened this issue 2 months ago • 0 comments

Suppose we have a sampleBy function that selects items from a list of pairs based on the second element value and then returns the selected first values. It takes a function of all the second values and returns their indices in the original list. This can be implemented as below:

sampleBy :: ([b] -> [Int]) -> [(a, b)] -> [a]
sampleBy f xs = map (at (map fst xs)) (f (map snd xs))

Where

-- lookup a value in a vector by index
at :: [a] -> Int -> a
fst :: (a, b) -> a
snd :: (a, b) -> b
map :: (a -> b) -> [a] -> [b]

The sampleBy implementation looks nice, however, when the code is generated, the map fst xs expression is re-evaluated at every index lookup. I want to force it to be evaluated only once. I can rewrite the expression as:

sampleBy f xs = map (at labels) (f (map snd xs)) where
  labels = map fst xs

But this evaluates to exactly the same code again, with labels being substituted into the main expression.

What would be nice is a means to force order of evaluation. Perhaps with let syntax?

sampleBy f xs =
  let labels = map fst xs
  let data = map snd xs
  map (at labels) (f data)

Where the compiler guarantees labels will be evaluated just once before the main expression. Adding let is a pretty major change.

Alternatively, we could define let as a source functions that forces evaluation:

let :: a -> (a -> b) -> b

This approach may serve as workaround until we implement real let handling.

arendsee avatar May 04 '24 23:05 arendsee