You seem to be right about the inlining. This seems to work

import Control.Monad (replicateM_)

fib :: Int -> Int
fib 0 = 0
fib 1 = 1
fib n = fib (n-1) + fib (n-2)
 
main = do
  n <- readLn
  fn <- return $! fib n -- force one and only one evaluation
  replicateM_ 20 (print fn)

Otherwise you can make inline fn more difficult (impossible?) with seq

   main = do
     n <- readLn
     let fn = fib n
     fn `seq` replicateM_ 20 (print fn)

Note that GHC seems to be too smart for itself and will inline something like flip const fn $ .... since it can see that const isn't strict in fn.

Cheers,
Danny Gratzer