import Test.QuickCheck
-- 1ª definición (por comprensión)
-- ===============================
suelo1 :: Float -> Integer
suelo1 x | x < 0 = head [m | m <- [-1,-2..], fromIntegral m <= x]
| otherwise = head [m | m <- [1..], x < fromIntegral m] - 1
-- 2ª definición (con until)
-- =========================
suelo2 :: Float -> Integer
suelo2 x | x < 0 = until (`menorI` x) (subtract 1) (-1)
| otherwise = until (x `menor`) (+1) 1 - 1
where menorI m x = fromIntegral m <= x
menor x m = x < fromIntegral m
-- 3ª definición (con until sin auxiliares):
suelo3 :: Float -> Integer
suelo3 x | x < 0 = until ((<=x) . fromIntegral) (subtract 1) (-1)
| otherwise = until ((x<) . fromIntegral) (+1) 1 - 1
-- 4ª definición (con show, read y takeWhile):
suelo4 :: Float -> Integer
suelo4 x | r < 0 = n-1
| otherwise = n
where n = read (takeWhile (/='.') (show x))
r = x - fromIntegral n
-- 5ª definición (con properFraction):
suelo5 :: Float -> Integer
suelo5 x = if r < 0 then n-1 else n
where (n,r) = properFraction x
-- 6ª definición (por búsqueda binaria):
suelo6 :: Float -> Integer
suelo6 x = fst (until unitario (mejora x) (acota x))
where inferior x = until (`menorI` x) (*2) (-1)
superior x = until (x `menor`) (*2) 1
menorI m x = fromIntegral m <= x
menor x m = x < fromIntegral m
acota x = (inferior x, superior x)
mejora x (m,n) = if p `menorI` x then (p,n) else (m,p)
where p =(m+n) `div` 2
unitario (m,n) = (m+1 == n)
-- La propiedad es
prop_suelo x =
suelo1 x == y &&
suelo2 x == y &&
suelo3 x == y &&
suelo4 x == y &&
suelo5 x == y &&
suelo6 x == y
where y = floor x
-- La comprobación es
-- ghci> quickCheck prop_suelo
-- +++ OK, passed 100 tests.