1) El problema es que sqrt
tiene el tipo (Floating a) => a -> a
, pero intenta utilizar un Entero como argumento. Por lo tanto, debe convertir su entero primero en flotante, p.escribiendo sqrt (fromIntegral x)
2) No veo ninguna razón por la cual == no deben ser perezoso, pero para la prueba de una colección vacía que puede utilizar la función null
(que es, sin duda perezoso, ya que trabaja en las listas infinitas):
isPrime :: Integer->Bool
isPrime x = null [y | y<-[2..floor (sqrt (fromIntegral x))], x `mod` y == 0]
Pero para obtener una solución más idiomática, divida el problema en sub-problemas más pequeños. En primer lugar, necesitamos una lista de todos los elementos y con y * y < = x:
takeWhile (\y -> y*y <= x) [2..]
entonces necesitamos sólo los elementos que dividen x:
filter (\y -> x `mod`y == 0) (takeWhile (\y -> y*y <= x) [2..])
entonces tenemos que comprobar si esa lista está vacío:
isPrime x = null (filter (\y -> x `mod`y == 0) (takeWhile (\y -> y*y <= x) [2..]))
Y si esto se parece a lispy a usted, reemplazar algunos de los parens con $
isPrime x = null $ filter (\y -> x `mod` y == 0) $ takeWhile (\y -> y*y <= x) [2..]
Para mayor claridad se puede "subcontratar" la lambdas:
isPrime x = null $ filter divisible $ takeWhile notTooBig [2..] where
divisible y = x `mod`y == 0
notTooBig y = y*y <= x
Se puede hacer casi "legible" mediante la sustitución del filtro $ nula con no $ ninguna:
isPrime x = not $ any divisible $ takeWhile notTooBig [2..] where
divisible y = x `mod`y == 0
notTooBig y = y*y <= x
La última declaración funciona para todos los números mayores o iguales a 2. Para 1 incorrectamente dice que es primo, ya que 1 no es primo. – Elmex80s