Haskell — Как написать (.) f f = (\x -> f (f x))

Мне нужно написать модуль для запуска на GHCi с функциональной композицией для той же функции. Это (классический fog(x) = f(g(x))) работает:

(.) f g = (\x -> f (g x)). 

Проблема появляется, когда я пытаюсь написать это так

(.) f f = (\x -> f (f x)).   (fof(x) = f(f(x)))

GHCI говорит:

"Conflicting definitions for `f'
 Bound at: Lab1.hs:27:9
           Lab1.hs:27:12"

Строка 27:9 появляется в первый раз, когда f, а строка 27:12 снова появляется f.

Почему Haskell не понимает (.) f f = (\x -> f (f x))?


person m4verick    schedule 22.09.2014    source источник
comment
Вы пытаетесь сопоставить шаблон для случая, когда оба аргумента равны? Потому что в этом случае у вас есть не только синтаксическая проблема (необходимо использовать разные имена для разных аргументов), но и концептуальная проблема (равенство функций, как правило, неразрешимо).   -  person DanielM    schedule 22.09.2014
comment
Вы хотите twice f = \x -> f (f x)?   -  person Tom Ellis    schedule 30.01.2015


Ответы (2)


В Haskell аргументы функции должны иметь уникальные имена. Использование того же имени для другого аргумента не допускается. Это потому что

foo x y = ...    ===    foo = (\x-> (\y-> ...))

и если y заменить на x, второй x просто затенит первый внутри тела ...: оттуда не будет возможности сослаться на первый x.

Вы можете просто определить twice f x = f (f x):

Прелюдия> :t дважды
дважды :: (t -> t) -> t -> t
Прелюдия> дважды (+1) 4
6


В качестве альтернативы f (f x) = (.) f f x = join (.) f x:

Prelude Control.Monad> :t join (.)
join (.) :: (b -> b) -> b -> b

join определяется в Control.Monad. Для функций считается, что join g x = g x x. Он также известен как W комбинатор.

Например. print $ join (.) (+1) 4 выводит 6.

person Will Ness    schedule 22.09.2014

Как говорится в сообщении об ошибке, у вас есть конфликтующие определения для f в определении (.) f f = (\x -> f (f x)). Вы привязываете имя f к первому и второму аргументам (.), поэтому ghci не знает, какой аргумент использовать при вычислении выражения f x.

Нет ничего плохого в том, чтобы определить (.) с помощью шаблона (.) f g, а затем вызвать его с двумя одинаковыми аргументами.

person sjy    schedule 22.09.2014
comment
Но мне нужно написать как (.) f f , я знаю, что (.) f g правильно написать, потому что я запускаю и проверяю GHCI. Я думаю, что это должна быть форма для правильного написания (.) f f, для меня это проблема синтаксиса. - person m4verick; 22.09.2014
comment
user3421938: нет, вы не можете этого сделать: λ пусть делает эту работу nope nope = nope ‹interactive›:44:18: Противоречивые определения для 'нет' Bound at: ‹interactive›:44:18-21 ‹interactive›:44: 23-26 В уравнении для «делает этоРаботает» - person rampion; 22.09.2014