content: approx
    :: Fractional a
    => (a1 -> a) -> [a1] -> [a] -> a
  approx f xs ws =
    sum
      [ w * f x
      | (x, w) <- zip xs ws ]
  
  integrateOpen
    :: Fractional a
    => a -> [a] -> (a -> a) -> a -> a -> Int -> a
  integrateOpen v vs f a b n = approx f xs ws * h / v
    where
      m = fromIntegral (length vs) * n
      h = (b - a) / fromIntegral m
      ws = concat $ replicate n vs
      c = a + h / 2
      xs =
        [ c + h * fromIntegral i
        | i <- [0 .. m - 1] ]
  
  integrateClosed
    :: Fractional a
    => a -> [a] -> (a -> a) -> a -> a -> Int -> a
  integrateClosed v vs f a b n = approx f xs ws * h / v
    where
      m = fromIntegral (length vs - 1) * n
      h = (b - a) / fromIntegral m
      ws = overlap n vs
      xs =
        [ a + h * fromIntegral i
        | i <- [0 .. m] ]
  
  overlap
    :: Num a
    => Int -> [a] -> [a]
  overlap n [] = []
  overlap n (x:xs) = x : inter n xs
    where
      inter 1 ys = ys
      inter n [] = x : inter (n - 1) xs
      inter n [y] = (x + y) : inter (n - 1) xs
      inter n (y:ys) = y : inter n ys
  
  uncurry4 :: (t1 -> t2 -> t3 -> t4 -> t) -> (t1, t2, t3, t4) -> t
  uncurry4 f ~(a, b, c, d) = f a b c d
  
  -- TEST ----------------------------------------------------------------------
  ms
    :: Fractional a
    => [(String, (a -> a) -> a -> a -> Int -> a)]
  ms =
    [ ("rectangular left", integrateClosed 1 [1, 0])
    , ("rectangular middle", integrateOpen 1 [1])
    , ("rectangular right", integrateClosed 1 [0, 1])
    , ("trapezium", integrateClosed 2 [1, 1])
    , ("simpson", integrateClosed 3 [1, 4, 1])
    ]
  
  integrations
    :: (Fractional a, Num t, Num t1, Num t2)
    => [(String, (a -> a, t, t1, t2))]
  integrations =
    [ ("x^3", ((^ 3), 0, 1, 100))
    , ("1/x", ((1 /), 1, 100, 1000))
    , ("x", (id, 0, 5000, 500000))
    , ("x", (id, 0, 6000, 600000))
    ]
  
  main :: IO ()
  main =
    mapM_
      (\(s, e@(_, a, b, n)) -> do
         putStrLn
           (concat
              [ indent 20 ("f(x) = " ++ s)
              , show [a, b]
              , "  ("
              , show n
              , " approximations)"
              ])
         mapM_
           (\(s, integration) ->
               putStrLn (indent 20 (s ++ ":") ++ show (uncurry4 integration e)))
           ms
         putStrLn [])
      integrations
    where
      indent n = take n . (++ replicate n ' ')
  