2014-11-01 2 views
2

Я знаю, что (.) f g x = f (g x). Предположим, что f имеет тип Int -> Int, g имеет тип Int -> Int -> Int. Теперь пусть h будет определяться h x y = f (g x y). Какое из следующих утверждений истинно и почему (почему бы и нет)?Смущенный функциональный состав в Haskell

a. h = f . g

b. h x = f . (g x)

c. h x y = (f . g) x y

Предположительно, только b. это правда, а остальные ложны. Я бы подумал. и b. эквивалентны ... a. говорит, что две функции равны. Две функции равны только тогда, когда я добавляю аргумент в конец обеих сторон, он все равно будет равен. Поэтому я получаю h x = f . g x. Теперь (.) является оператором, поэтому функциональное приложение имеет приоритет над ним, поэтому f . g x = f . (g x), что и b.

+8

Я что-то упустил? Если 'g' имеет тип' Int-> Int-> Int', то 'g x' имеет тип' Int-> Int', а 'f (g x)' - ошибка типа. – Joni

+2

Возможно, вы имели в виду, что 'h' определяется' h x y = f (g x y) '? – AndrewC

+0

BTW, добро пожаловать в переполнение стека! Это часто помогает, если вы некоторое время болтаете, прося отвечать на комментарии, так как это ускоряет работу. По общему признанию, мы не очень быстро реагировали на этот раз. – AndrewC

ответ

4

Это выглядит как домашнее задание, поэтому я не буду давать ответ, какой из них правильный.

Вы считаете a и b идентичными неправильно. Если f . g применяется к x, вы получите (из определения (.))

(f . g) x = f (g x) 

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

+0

ОК, это имеет смысл, спасибо. Итак, мое текущее понимание выглядит следующим образом [это правильно?]: (A) истинно iff 'h x = (f. G) x', что является' f (g x) '. Это неверно напечатано, потому что 'g x :: Int -> Int', но' f' требует ввода 'Int'. (B) Они являются функциями 'Int -> Int', поэтому b. истинно, если hh y = (f. (g x)) y', то есть defn. funcl. compn. 'f (g x y)', который является 'h x y'. Так что это правда. (C) 'h x y = (f. G) x y = f (g x)' y, который неправильно вводится по той же причине, что и a. Если эти объяснения верны, мы можем опубликовать их как ответ на мой вопрос. :) –

+0

@DominikTeiml, чтобы решить, будет ли expA = expB, нам сначала нужно выяснить, является ли какое-либо из выражений * хорошо сформированным *, которое в Haskell означает «имеет тип». Если я пишу 'head head', это выражение не имеет типа, т. Е. Плохо сформировано. gven типы для 'f' и' g', выражение 'f. ... плохо образован? хорошо сформированные? (выберите правильный ответ). –

+0

@DominikTeiml В исправленном вопросе есть 'h x y = f (g x y)', поэтому 'b' истинно. –

0

первоначальное определение композиции функций является немного запутанным, так что я буду писать это по-другому:

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

Это означает, что f . g возвращает функцию, которая первая применяет аргумент g, затем применяет результат это до f. Это также ясно, в сигнатуре типа:

(.) :: (b -> c) -> (a -> b) -> (a -> c) 

Теперь для функции Н, он имеет тип что-то вроде h :: a -> a -> a. Помните, что -> является право-ассоциативным, поэтому тип может быть записан как h :: a -> (a -> a). По существу, h :: a -> b, хотя этот тип вызовет ошибку, потому что b и a являются необратимыми. (.) только позволит один аргумент, который будет применен к первой функции, так:

-- One could write, 
h x y = f (g x y) 
-- But One could also write 
h x = f . g x 
-- Or, more clearly: 
h x = (f) . (g x) 

Это происходит потому, что функции Haskell являются кэрри, поэтому мы можем применить некоторые аргументы g без полной оценки его.

Если мы представим себе, что произойдет, если мы применили (.) визуально, то упростить, мы можем увидеть, как это работает:

h x = \a -> f ((g x) a) 
h x = \a -> f (g x a) 
h x a = f (g x a) 

Так что да, б ответ. Это связано с тем, что (.) разрешает применять только один аргумент к первой функции перед переходом к следующему.

Теперь вы можете справиться с другими неправильными решениями, упростив, как и я. Это не слишком сложно.

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