-- 1ª definición
-- =============
antiimagen1 :: (Int -> Int) -> Int -> Maybe Int
antiimagen1 f y
| estaEnImagen f y = Just x
| otherwise = Nothing
where x = head [x | x <- [0..], f x == y]
-- (estaEnImagen f y) se verifica si pertenece a la imagen de f. Por
-- ejemplo,
-- estaEnImagen (^2) 25 == True
-- estaEnImagen (^2) 30 == False
estaEnImagen :: (Int -> Int) -> Int -> Bool
estaEnImagen f y = elem y (takeWhile (<=y) (imagen f))
-- (imagen f) es la imagen de f. Por ejemplo,
-- take 10 (imagen (^2)) == [0,1,4,9,16,25,36,49,64,81]
-- take 10 (imagen (*3)) == [0,3,6,9,12,15,18,21,24,27]
imagen :: (Int -> Int) -> [Int]
imagen f = map f [0..]
-- 2ª definición (con lookup y maxBound)
-- =====================================
antiimagen2 :: (Int -> Int) -> Int -> Maybe Int
antiimagen2 f y =
lookup y (takeWhile (<= (y,maxBound)) [(f x, x) | x <- [0..]])