OCAML: разница между let func ax = (ax) ;;и пусть func ax = ((fun a -> a) x) ;;? - PullRequest
0 голосов
/ 21 октября 2011

Я немного застрял в этом задании для 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.

Но когда я изменяю утверждение на это, я получаю только значение, которое я поместил для x. Как я могу получить (весело a -> a) принять значение x?

let test a x = ((fun a -> a) x);;

Ответы [ 2 ]

4 голосов
/ 21 октября 2011

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 являются разными переменными. Первый никогда не используется позже. Вы можете переписать эту строку для более легкого понимания как:

let test a x = ((fun b -> b) x);;

Как получить (забавно a -> a) значение x?

Да, и в этом проблема. Вы передаете свой x в функцию идентификации и получаете x обратно. Что вы хотите сделать, это передать x вашей функции a, и это то, что вы сделали в своей первой попытке:

let func x = x + x;;
let test a x = a x;;
test func 3;;
  => 6
1 голос
/ 21 октября 2011

В простых случаях с функциональными языками часто бывает полезно написать выражение в форме, подобной лямбда-исчислению, и выполнить сокращения вручную (отмечая, какие сокращения вы используете). Вы по-прежнему можете использовать синтаксис 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. Попытка сделать это на первый взгляд может показаться очень необычной и сложной, но все становится проще и быстрее. Если вы сделаете что-то подобное пару раз, вы станете намного лучше в понимании общих функциональных шаблонов и рассуждениях о структуре вашей программы.

Посмотрите эту статью , чтобы получить больше примеров по этому вопросу.

Также обратите внимание, что при небольшом усилии это работает и в обратном направлении. Хотя обычно это не так полезно, как делать это в том же направлении, что и компилятор.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...