Этот код не принимается;
> fun fact 0.0 = 1.0
Error-Real constants not allowed in patterns
> | fact n = n*fact(n-1);
Static Errors
Почему это?
Этот код не принимается;
> fun fact 0.0 = 1.0
Error-Real constants not allowed in patterns
> | fact n = n*fact(n-1);
Static Errors
Почему это?
real
не является типом равенства. SML делает ставку на создание доказуемо правильного кода. Сравнение двух действительных чисел на равенство чаще всего является плохой идеей, поскольку может быть так, что x = y
математически, но из-за ошибки округления x != y
во время выполнения. Это печально известный источник ошибок в наивных реализациях численных алгоритмов. Поскольку это так часто бывает плохой идеей, SML просто запрещает ее. Поскольку таким образом невозможно сравнить ввод на равенство с шаблоном 1.0
, не имеет смысла разрешать его в качестве шаблона.
В относительно немногих случаях, когда вы действительно хотите сравнить два действительных числа на равенство, вы можете использовать x <= y andalso x => y
. В качестве альтернативы (как указывает @AndreasRossberg) можно использовать стандартную библиотечную функцию Real.==
, которая используется как Real.==(x,y)
. Последнее выглядит немного странно, поэтому вы можете объявить его как инфиксный оператор:
val == = Real.==
infix 4 ==
а затем просто x == y
К сожалению, ни один из них нельзя превратить в шаблон, хотя они позволяют написать:
fun fact x = if x == 0.0 then 1.0 else x * fact(x-1.0)
который работает, как, возможно, задумано. С другой стороны, как указывает @SimonShine, это приведет к сбою, если вы подадите ему любой ввод, который не имеет форму n.0
, где n
— целое число (даже если это происходит только из-за округления). ошибка выключения). Это именно та проблема, которую пытались предотвратить создатели SML. Гораздо разумнее определить fact
для получения и возврата целых чисел:
fun fact x = if x = 0 then 1 else x * fact(x-1)
(или -- почитайте о гамма-функции, если вам действительно нужен факториал с плавающей запятой).
Это последнее определение может быть легко преобразовано в форму сопоставления с образцом, которую вы, казалось, пытались получить.
Real.==
, если вы явно этого хотите.
- person Andreas Rossberg; 08.12.2016
fun fact x = if x == 0.0 then ...
, но если по какой-то причине ввод x
округлен неправильно, эта функция выдаст Out_of_memory
. Плавающие значения должны быть сопоставлены должным образом. :-)
- person Simon Shine; 09.12.2016
real
больше не допускает равенство в SML '97, заключается в том, что IEEE 754, который определяет числа с плавающей запятой, определяет их равенство непоследовательным образом; например, если x
равно NaN, то Real.==(x, x)
ложно! (SML '90 не указывал, как будет вести себя =
при задании NaN, и не предлагал отдельный примитив для равенства с плавающей запятой IEEE 754, поэтому меня не удивит, если некоторые реализации обрабатывают его одним способом, а некоторые реализации другой.)
- person ruakh; 18.12.2016
real
s этот ответ. - person Simon Shine   schedule 08.12.2016