#function #parameters #ocaml
#функция #параметры #ocaml
Вопрос:
Я немного застрял на этом задании для OCAML. Я пытаюсь передать функцию и значение в качестве параметра в другую функцию. Например, у меня есть функция с именем test, которая принимает (fun x -> x x) и 3 в качестве параметров. Функциональный тест должен вывести 6, поскольку 3 3 = 6. Я знаю, что могу добиться чего-то подобного, выполнив:
let func x = x x;;
let a = func;;
let test a x = (a x);;
Таким образом, когда я ввожу, проверяю 5, я получу 10.
Но когда я меняю оператор на this, я получаю только значение, которое я ввел для x. Как мне заставить (fun a -> a) принимать значение x?
let test a x = ((fun a -> a) x);;
Ответ №1:
fun a -> a
является анонимной функцией идентификации, она всегда будет возвращать свой параметр. Вы могли бы сказать:
let id = fun a -> a;;
id 3;;
=> 3
id (fun x -> x x);;
=> (fun x -> x x)
Обратите внимание, что в вашем
let test a x = ((fun a -> a) x);;
первая a
и две другие a
s являются разными переменными. Первый никогда больше не используется позже. Вы можете переписать эту строку для облегчения понимания как:
let test a x = ((fun b -> b) x);;
Как мне заставить (fun a -> a) принимать значение x?
Вы есть, и в этом проблема. Вы передаете свою x
функцию идентификации и x
возвращаетесь. То, что вы хотите сделать, это передать x
вашей a
функции, и это то, что вы сделали в своей первой попытке:
let func x = x x;;
let test a x = a x;;
test func 3;;
=> 6
Ответ №2:
С функциональными языками в простых случаях часто бывает полезно записать выражение в форме, подобной лямбда-исчислению, и выполнить сокращения вручную (отметив, какие сокращения вы используете). Вы все равно можете использовать синтаксис OCaml как упрощенную версию лямбда-исчисления
Итак, в случае вашего примера это станет:
let test a x = ((fun a -> a ) x);;
=> let test a x = ((fun b -> b ) x);; (* Variable renamed (alpha equivalence) *)
=> let test a y = ((fun b -> b ) y);; (* Variable renamed (alpha equivalence) *)
let func x = x x;;
Обратите внимание, что эти шаги служат только для того, чтобы убедиться, что в дальнейшем у нас не будет переменных с одинаковыми именами, ссылающихся на разные значения. Эти шаги можно не учитывать, но лично мне гораздо больше нравится работать с уникальными переменными.
test func 5
=> test (fun x -> x x) 5 (* Variable func inserted (beta reduction) *)
=> (fun a y -> ((fun b -> b) y) (fun x -> x x) 5 (* Variable test inserted *)
=> (fun y -> (fun b -> b) y) 5 (* Variable a inserted *)
=> ((fun b -> b) 5 (* Variable y inserted *)
=> 5 (* Variable b inserted *)
Конечный результат таков 5
. Попытка сделать это поначалу покажется очень необычной и трудной, но сделать это проще очень быстро. Если вы сделаете что-то подобное пару раз, вы намного лучше поймете общие функциональные шаблоны и рассуждения о структуре вашей программы.
Посмотрите на эту статью для получения дополнительных примеров по этому вопросу.
Также обратите внимание, что с немного большим усилием это работает и в обратном направлении. Хотя обычно это не так полезно, как делать это в том же направлении, что и компилятор.