Q:

Calculate multiple cutoff percentages for an Int list in Haskell?

I would like to write a Haskell function for the following problem: Given two list of Integers ("depths" and "thresholds"), return the mean depth and the fractional of depths greater or equal for each threshold.
As an example, given the depths [10,10,10,15,15,20] and the tresholds [10,15,20], the expected result should be [13.333333,1.0,0.5,0.16666667] (mean depth is 13.3, 100% of depths >= 10, 50% of depths >= 15 & 17% of depths >=20).
An imperative pseudo code solution could look like this:
-- getMeanAndPercents (thresholds, depths):
--  sum = 0
--  threshold_counts = [0 for t in thresholds]
--  len = 0
--  for d in depths:
--   sum += d
--   len += 1
--   for t in thresholds:
--    if d >= t: tresholds_counts[t] += 1
--  for t in tresholds
--   threshold_percents[t] = thresholds_counts[t] / len
--  return = [sum / len] + [threshold_percents]

My Haskell solution looks like this:
getMeanAndPercents :: [Int] -> [Int] -> [Float]
getMeanAndPercents thresholds depths = let
    depths2 = map f depths -- replace each depth d with [d, 1, 0, 1, 0, 1, 0, 0, ...]
    counts = foldl1 (zipWith (+)) depths2 -- sum the inner lists
    len = fromIntegral $ length depths -- get total depth length
                                       in fromIntegral (head counts) / len : map (\c -> fromIntegral c / len) (tail counts)
    where
        f d = d : map (\t -> if d >= t then 1 else 0) thresholds

Questions:
1) How should this code be indented (I'm unsure how to mix let ... in with where)?
2) How often Haskell will loop over depths? I would assume once for length and once for foldl1 & map.
3) What would be a better (w.r.t. performance and/or readability)  implementation in Haskell? (I assume one needs to do at least O(d*t), i.e. loop over all thresholds for all depths)
EDIT: The depths are not ordered, the thresholds could be ordered by the function. Thus, one could skip >= once the first threshold fails the test.

A:

How should this code be indented?
That is subjective- personally I prefer this:
getMeanAndPercents :: [Int] -> [Int] -> [Float]
getMeanAndPercents thresholds depths
  = let depths2 = map f depths
        counts  = foldl1 (zipWith (+)) depths2
        len     = fromIntegral $ length depths
    in fromIntegral (head counts) / len : map (\c -> fromIntegral c / len) (tail counts)
 where f d = d : map (\t -> if d >= t then 1 else 0) thresholds

How often Haskell will loop over depths? I would assume once for length and once for foldl1 & map.
Lists in Haskell are not actually lists, but rather lazy streams of data, like a generator in an imperative language like python.
Because the computation depends on the length of the stream, we have to go trough it once to see how long it is, which also forces you to load the entire list into memory.
You loop trough the depth list once for each item in the threshold list, and another time to get the sum, so this is O(2d+dt).
If you actually know the length of the list you should pass it in to the function, or you could use another datatype like Array where the length is already known.
What would be a better (w.r.t. performance and/or readability) implementation in Haskell? (I assume one needs to do at least O(d*t), i.e. loop over all thresholds for all depths)
I would have written your implementation like this:
getMeanAndPercents :: [Int] -> [Int] -> (Float, [Float])
getMeanAndPercents thresholds depths
  | len    <- fi $ length depths
  , (c:cs) <- foldl1 (zipWith (+)) $ f <$> depths
  = (fi c / len, (/len).fi <$> cs)
 where f d = d : map (\t -> if d >= t then 1 else 0) thresholds
       fi  = fromIntegral

This is closer to your imperative code:
getMeanAndPercents thresholds depths
  | ((sum, len), ts) <- mapAccumL
      ( \(sum, len) d -> ( (sum+d, len+1)
                         , map (\t -> if d>=t then 1 else 0) thresholds
                         )
      ) (0,0) depths
  = (/len) <$> (sum:foldl1(zipWith(+))ts)

This is more readable/ideomatic haskell:
getMeanAndPercents :: [Int] -> [Int] -> (Float, [Float])
getMeanAndPercents thresholds depths
  | len <- length depths
  = ( sum depths / len
    , [ length (filter (>=t) depths) / len | t <- thresholds ]
    )

