Я думаю, что код, который вы предоставили, является самым быстрым, что вы собираетесь получить:
is_square n = sq * sq == n
where sq = floor $ sqrt $ (fromIntegral n::Double)
Сложность этого кода: один sqrt, одно двойное умножение, одно приведение (dbl-> int) и одно сравнение. Вы могли бы попытаться использовать другие методы вычисления, чтобы заменить sqrt и умножение только целочисленной арифметикой и сдвигами, но есть вероятность, что это не будет быстрее, чем один sqrt и одно умножение.
Единственное место, где стоит использовать другой метод, - это если процессор, на котором вы работаете, не поддерживает арифметику с плавающей запятой. В этом случае компилятору, вероятно, придется генерировать sqrt и двойное умножение в программном обеспечении, и вы можете получить преимущество в оптимизации для вашего конкретного приложения.
Как указывает другой ответ, по-прежнему существует ограничение больших целых чисел, но если вы не собираетесь сталкиваться с этими числами, вероятно, лучше воспользоваться преимуществами аппаратной поддержки с плавающей запятой, чем писать собственный алгоритм.