Search code examples
listhaskellscalelogarithm

Splitting a list in non-equal width chunks in Haskell


I am trying to do something like in Haskell:

mkList start end nb_chunck will output [start, boun1, bound2, bound3 ..., end]

However I don't want to split the list in equal-size chunk but to follow a logarithmic scale.

The C algorithm I want to transform in Haskell is availabke here: How to get a logarithmic distribution from an interval

I don't really know how to do it.

Here's what I have attempted so far:

mkList :: Int -> Int -> Int -> Int -> Int -> [Int]
mkList _ _ _ _ 7 = []
mkList lower upper start end n = [lower, ((fromIntegral (log(2 + (fromIntegral n :: Int)) )+start) * scale)] ++ (mkList (fromIntegral(((fromIntegral (log(2 + (fromIntegral n :: Int)) )+start) * scale)+1) :: Int) ((fromIntegral (log(2 + (fromIntegral (n) :: Int)) )+start) * scale) (start) end (fromIntegral (n+1) :: Int)) where
scale = (end - start) `quot` floor(log(1 + (6)))

However, I can't validate this code, because when I compile, error messages pop up:

haskell_par3.hs:71:58:
No instance for (Floating Int) arising from a use of `log'
Possible fix: add an instance declaration for (Floating Int)
In the first argument of `fromIntegral', namely
  `(log (2 + (fromIntegral n :: Int)))'
In the first argument of `(+)', namely
  `fromIntegral (log (2 + (fromIntegral n :: Int)))'
In the first argument of `(*)', namely
  `(fromIntegral (log (2 + (fromIntegral n :: Int))) + start)'
ghc -cpp: /usr/hs/ghc/7.6.3/bin/ghc failure (return code=1)

I've tried to make use of fromIntegral at different spots but it didn't help, as seen in other answered questions on StackOverflow.

So I'm asking two things:

  • Do you have any precise idea of how I could fix these compilation errors? (I know it has something to do with fromIntegral, but I can't get rid of this error).
  • And more important: Do you think this code may achieve what I want to do? If no, do you have any suggestions?

Solution

  • you can do something like this to create a log scale intervals

    scale k n = map (floor . (*k) . (/(log n)) . log) [1..n]
    

    e.g.

    scale 100 9
    [0,31,50,63,73,81,88,94,100]
    

    and use the indices to partition the array by start/end indices.

    You can cast the output to [Int] since floor convert it to an Integral type

    Prelude> scale 10 3 :: [Int]
    [0,6,10]
    Prelude> :t it
    it :: [Int]