В SML почему вы не можете использовать реальную константу в шаблоне?

Этот код не принят;

> fun fact 0.0 = 1.0
Error-Real constants not allowed in patterns
> | fact n = n*fact(n-1);
Static Errors

Почему это?

1 ответ

Решение

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 это int (даже если это только из-за ошибки округления). Это именно та проблема, которую создатели SML пытались предотвратить. Это имеет гораздо больше смысла, чтобы определить fact взять и вернуть целые:

fun fact x = if x = 0 then 1 else x * fact(x-1)

(или - читайте о гамма-функции, если вы действительно хотите факториал с плавающей точкой).

Последнее определение можно легко преобразовать в форму сопоставления с образцом, которую вы, похоже, пытались найти.

Другие вопросы по тегам