Анонимная функция больше не является анонимной, когда вы связываете ее с
переменная. А поскольку val rec
- это просто производная форма fun
без
Разница, кроме внешнего вида, вы могли бы написать это с помощью
синтаксис fun
. Также вы можете сделать поиск по шаблону в fn
выражениях
как в case
, так как случаи получены из fn
.
Итак, во всей своей простоте вы могли бы написать свою функцию как
val rec fact = fn 0 => 1
| x => x * fact (x - 1)
но это точно так же, как ниже, более читабельно (по моему мнению)
fun fact 0 = 1
| fact x = x * fact (x - 1)
Насколько я думаю, есть только одна причина, чтобы использовать написать свой код, используя
long val rec
, и это потому, что вы можете легче комментировать свой код с
комментарии и принудительные типы. Например, если вы уже видели код на Haskell и
как способ, которым они печатают, комментируют свои функции, вы могли бы написать это что-то
как это
val rec fact : int -> int =
fn 0 => 1
| x => x * fact (x - 1)
Как уже упоминалось в templatetypedef, это можно сделать с помощью фиксированной точки
комбинатор. Такой комбинатор может выглядеть как
fun Y f =
let
exception BlackHole
val r = ref (fn _ => raise BlackHole)
fun a x = !r x
fun ta f = (r := f ; f)
in
ta (f a)
end
И затем вы можете рассчитать fact 5
с помощью приведенного ниже кода, который использует анонимный
функции, чтобы выразить функцию факультета, а затем связывает результат
вычисление до res
.
val res =
Y (fn fact =>
fn 0 => 1
| n => n * fact (n - 1)
)
5
Код с фиксированной запятой и пример вычисления любезно предоставлены Мортеном Бронс-Педерсеном.
Обновленный ответ на ответ Джорджа Кангаса:
На известных мне языках рекурсивная функция всегда будет привязана к
название. Удобный и обычный способ обеспечивается такими ключевыми словами, как
"define", или "let", или "letrec", ...
Тривиально верно по определению. Если функция (рекурсивная или нет) не связана с именем, она будет анонимной.
Нетрадиционный, более анонимный способ - лямбда-связывание.
Я не вижу ничего необычного в анонимных функциях, они все время используются в SML, фактически на любом функциональном языке. Его даже начинают появляться на все более и более императивных языках.
Ответ Джеспера Ринберга показывает лямбда-связывание; «анонимный»
функция связывается с именами "f" и "fact" с помощью лямбды (называемой
"fn" в SML).
Анонимная функция на самом деле является анонимной (не «анонимной» - без кавычек), и да, конечно, она будет связана в scope с любой функцией, на которую она передается в качестве аргумента. В любых других случаях язык был бы совершенно бесполезным. То же самое происходит при вызове map (fn x => x) [.....]
, в этом случае функция анонимной идентификации все еще фактически анонимна.
«Нормальное» определение анонимной функции (по крайней мере, согласно wikipedia ), говорящее, что она не должна быть привязана к идентификатору, немного слабое и должно включать неявное выражение «в текущая среда ".
Это на самом деле верно для моего примера, как видно из его запуска в mlton с аргументом -show-based для файла, содержащего только fun Y ...
и val res ..
val Y: (('a -> 'b) -> 'a -> 'b) -> 'a -> 'b
val res: int32
Из этого видно, что ни одна из анонимных функций не связана в среде.
Более короткая альтернатива "lambdanonymous", которая требует запуска OCaml
от "ocaml -rectypes":
(fun f n -> f f n)
(fun f n -> if n = 0 then 1 else n * (f f (n - 1))
7;; Which produces 7! = 5040.
Похоже, вы совершенно не поняли идею оригинального вопроса:
Можно ли писать рекурсивные анонимные функции в SML?
И простой ответ - да. Сложный ответ (среди прочего?) Является примером того, как это делается с использованием комбинатора с фиксированной точкой, а не «лямбданонимным» (что бы это ни значило) примером, выполненным на другом языке, с использованием возможностей, даже удаленных в SML. *