Haskell — Как дважды написать функцию, используя (.) f g — композиция функций

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

(twice= \x-> \x-> x) 

но на этот раз с использованием функции композиции (.), такой как (.) f g.

Я не знаю, как это решить, потому что я думал в начале сделать так:

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

с (g = f) так будет вот так

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

но у меня есть

"Противоречивые определения для `f'"

работает на GHCI

Итак, есть предложения?


person m4verick    schedule 22.09.2014    source источник
comment
Я думаю, что у вас нет правильного базового синтаксиса для Haskell (пока) - это похоже на смесь лямбда-исчисления и синтаксиса Haskell - возможно, вы можете написать немного больше о том, откуда это взялось. А пока вы можете взглянуть на мой ответ, чтобы увидеть, как я предполагаю twice и решаю его.   -  person Random Dev    schedule 22.09.2014
comment
Хорошо, вот в чем дело, я на самом деле изучаю новый курс, он называется «Основы вычислений» и, как вы упомянули, представляет собой смесь лямбда-исчисления и языка Haskell. Они пытались научить двум вещам. My дважды дважды применяет функцию f к аргументу x. Затем они просят меня решить проблему, но на этот раз с помощью функции композиции (.). Мне очень сложно из-за того, что вы упомянули: они все время смешивают Haskell и лямбда-исчисление.   -  person m4verick    schedule 22.09.2014
comment
И действительно, это легко, если вы правильно понимаете twice   -  person Random Dev    schedule 22.09.2014
comment
То же самое и в лямбда-исчислении - попробуйте уменьшить (((\x.(\x.x)) f) x) - есть ли в результате f?   -  person Random Dev    schedule 22.09.2014
comment
(Подсказка: это более или менее то же самое, что упоминается в моем ответе сразу после начала)   -  person Random Dev    schedule 22.09.2014
comment
возможный дубликат Haskell - Как писать (.) f f = (\ x -> f ( ф х)) - Правильно   -  person High Performance Mark    schedule 22.09.2014
comment
@HighPerformanceMark Я не думаю, что это дубликат - похоже, у него есть дополнительная проблема борьбы с twice и синтаксисом   -  person Random Dev    schedule 22.09.2014
comment
Мне это кажется двумя вариантами одной и той же проблемы — как определить состав двух функций, когда эти две функции могут быть одинаковыми.   -  person High Performance Mark    schedule 22.09.2014


Ответы (1)


Я не знаю, как вы получили что-то кроме ввода синтаксического анализа из этого:

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

но определение, которое вы дали: twice = \x -> \x -> x не имеет ничего общего с использованием чего-то «дважды» - действительно, если вы подставите некоторые значения:

twice a b
= (\x -> \x -> x) a b 
= (\x -> (\x -> x)) a b -- (rename the inner x)
= (\x -> (\y -> y)) a b
= ((\x -> (\y -> y)) a) b
= (\y -> y) b
= b

и действительно GHCi скажет вам то же самое:

> let twice = \x -> \x -> x
> :t twice
twice :: t -> t1 -> t1
> twice "a" "b"
"b"

Теперь я думаю, вы хотите что-то вроде этого:

let twice f x = f (f x)

Например:

> let twice f x = f (f x)
> twice (+1) 5
7

как видите, twice (+1) добавляет 2 (или дважды один).

Теперь, как вы можете сделать это, используя (.)? - Что ж, твоя интуиция не подвела:

> let twice f = f . f
> twice (+1) 5
7

относительно модуля

Поскольку вы просили модуль - он отлично компилируется (и загружается в GHCi) в моей системе (системах):

module Twice where

twice :: (a->a) -> a -> a
twice f = f . f

замечание:

это работает, только если вы включаете (.) из прелюдии (или GHC.Base) - я подозреваю, что вы получили какое-то упражнение, скрывающее прелюдию - в этом случае вы должны сначала определить (.) для себя (скорее всего, другое упражнение)

если вам нужно реализовать это самостоятельно:

(.) :: (b -> c) -> (a -> b) -> a -> c
(.) g f x = g (f x)
person Random Dev    schedule 22.09.2014
comment
Мой дважды такой: дважды:: (а -> а) -> а -> а дважды = \х-> \х-> х. И работает нормально, потому что зонд делает это дважды не False = False, я имею в виду дважды не False = не не False = False. Так что теперь мне нужно написать эту версию дважды, но используя нотацию (.), я надеюсь, что это будет более ясно, и спасибо за ваш ответ. - person m4verick; 22.09.2014
comment
err - нет... попробуйте использовать вашу функцию с twice (+1) 0 и она даст 0 (я даже показал вам почему) - person Random Dev; 22.09.2014
comment
Это работает для вашего примера только потому, что не . not == id, поэтому вы думаете, что ваше определение подходит только потому, что оно является идентификатором для второго аргумента. Вы можете сказать, что что-то не так, потому что вы никогда не используете первый аргумент, который вы указываете (почему вы могли бы спросить? Ну, потому что вы затеняете первый x вторым \x -> x - person Random Dev; 22.09.2014
comment
Хорошо, я понял смысл, и вы хорошо, что это должно быть: дважды f x = f (f x). Но другая проблема заключается в том, что когда я сохраняю это другое обозначение: дважды f = f . f - GHCI говорит мне Не входит в объем: `.' любое другое предложение? - person m4verick; 22.09.2014
comment
попробуй let twice f = f . f ^^ - person Random Dev; 22.09.2014
comment
Я должен писать по модулю — говорю вам, потому что, возможно, вы думаете, что я пишу непосредственно по GHCI. Это не сработало, когда я загружаюсь на GHCI, кажется, это не понравилось. они сказали: Lab1.hs:29:14: Не входит в объем: `.' где строка 29: пусть дважды f = f . спасибо за вашу помощь - person m4verick; 22.09.2014
comment
это не должно быть проблемой - попробуйте скопировать дополнение к моему ответу directyl в файл (сохраните его как Twice.hs) и загрузите это - это работает как на моих окнах, так и на моей виртуальной машине Linux здесь - person Random Dev; 22.09.2014
comment
BTW: какие остальные файлы... ты что-то скрывал от прелюдии? - person Random Dev; 22.09.2014
comment
Вы снова в порядке, я вышел из линии импорта Prelude (Show), и она сработала отлично. Я надеюсь, что все будет хорошо, я так думаю. Большое спасибо за Вашу помощь. - person m4verick; 22.09.2014