There are at least two ways to solve this problem linearly in time.
Using intermediate memory
c1 :: Integer -> Integer
c1 n
| n <= 4 = n + 10
| otherwise = go n (map c1 [4,3,2,1])
where
go 4 (a:_) = a
go n [a,b,c,d] = go (n-1) [a + 2*d, a, b, c]
Here we use four intermediate registers and shift them while go
ing through the cycle. We could use tuple (a, b, c, d)
instead of a list, but it is more handy to start with mapping here.
This solution is constant in space and linear in time.
Memoization (codata generation)
c2 :: Integer -> Integer
c2 n
| n <= 4 = n + 10
| otherwise = results !! fromInteger (n - 1)
where
results = [11..14] ++ zipWith f (drop 3 results) results
f a b = a + 2*b
Here we use the laziness of Haskell (normal evaluation strategy + memoization). The infinite list results
generates values one-by-one on demand. It is used as data by c2
function which just requests the generator for n
-th number, and in self-definition. At the same time this data does not exist until it is needed. Such sort of data is called codata and it is rather common in Haskell.
This solution is linear in space and time.
Both solutions handle negative numbers and large positive numbers.