2013-06-06 6 views
1
карри

У меня есть функцияF # Интересное поведение функции

// Will perform a given function twice 
let twice f = (fun x -> f (f x)) 

Тогда у меня есть что-то подобное.

// Take x add 1 
let f x = x+1 

В зависимости от того, как я называю дважды, он ведет себя по-разному, чтобы левая ассоциативность.

(twice (twice (twice (twice f)))) 0;; // Outputs 16 
twice twice twice twice f 0;; // Outputs 65536 

Если я добавить еще дважды моя программа делает StackOverflow, но до сих пор, кажется, ведут себя без рисунка, который сводит меня с ума.

Позволяет k быть числом twice.

Для того, чтобы получить ответ, вы получите нетоварный 2^k.

Curried чрезвычайно странный. Гипотеза 1: Когда число вызовов меньше, чем 4 выглядит как 2^(2^(к-1)), но при к 4 она ведет себя как 2^(2^к)

ли кто-нибудь увидеть шаблон? Или вы можете запустить его мимо k = 4, чтобы доказать это?

+0

Хотя это интересная головоломка, я не верю, что это подходящий форум для обмена такого рода вещами. Голосовать, чтобы закрыть. –

+0

Пожалуйста, объясните. –

+1

«Я отправлю ответ в 24 часа, если этого не будет. Удачи!» Есть сайты для программирования головоломок; StackOverflow не такой сайт. –

ответ

2

Это простые правила приоритета, которые ведут себя странно (намек 65536 = 2^16). Во втором случае вы фактически создаете экспоненциальное число вызовов f, а не линейное увеличение, которое вы ожидали.

Когда вы расширяете один слой на втором случае вы получите

twice twice twice (twice twice twice (f)) 0 

и число членов будет расти в геометрической прогрессии, как вы пишете больше twice

+0

Да, это связано с функциями, связанными с левым, право? –

+0

Да, это как раз то, как F # обрабатывает вещи, написанные в таком порядке. –

1

В самом деле, это все о ассоциативности. Когда вы пишете,

let x1 = twice twice twice twice f 0 

Это равно

let x11 = (((twice twice) twice) twice) f 0 

Это приводит к экспоненциальному росту порядка вызова: каждый twice вызов должен вызвать f x два раза. Вместо этого он рекурсивно называет себя, и только самый внутренний вызов будет ссылаться на f.

Вы можете посмотреть на прототип функции:

let y1: (_ -> _ -> int) = twice twice twice twice 
// val y1: ((int -> int) -> int -> int) 

Минимальный код, чтобы сделать ассоциативности работу хорошо бы:

// note we need to specify a type here 
let y2: (_ -> _ -> int) = twice >> twice >> twice >> twice 
// the same with all arguments 
let x2 = (twice >> twice >> twice >> twice) f 0 

или

let y3 = f |> twice |> twice |> twice |> twice 
let x3 = (f |> twice |> twice |> twice |> twice) 0 
+0

Мне кажется странным. Почему он рекурсирует? пусть дважды f = f >> f. пусть t1 = дважды в два раза, так что t1 дважды возвращается дважды. пусть t2 = дважды >> дважды. Почему t1 ведет себя иначе, чем t2? – tomasK

+0

@tomasK 'дважды >> ... >> дважды' и 'дважды ... дважды' выглядят иначе (линейно и экспоненциально, соответственно). Они получают равные значения только в том случае, если они применяются два раза точно, потому что '2 * 2 = 2^2'. – bytebuster

+0

Уверенный результат ясен, но у меня есть проблема представить, как и почему он вызывается в exp. манера. Я попытался указать, что дважды дважды получается результат дважды дважды, поэтому я не понимаю, почему он растет экспоненциально в этом случае, когда он выглядит практически так же, как ваш линейный случай дважды >> дважды. – tomasK

Смежные вопросы