2014-10-08 3 views
2

Я уверен, что это довольно очевидно, но несите меня, я новичок в этом, и он не щелкает. Так что, как и многие другие люди, я пытался склонить голову над Монадами. Я дошел до того, что мне удобно с операторами >> = и возвращать, и так далее. Но я чувствую, что я не пойму этого, пока не получу это и не напишу сам.Задание аргумента функции по типу

Следовательно, я играл с попыткой реализовать оператор bind >> = для списка как состав карты и foldr. Например, [5,6,7,8] >>= (\x -> [x*5, x*6, x*7]) дает [25,30,35,30,36,42,35,42,49,40,48,56]. Это очень похоже на состав карты и складку. Но если я попробую что-то вроде foldr (++) [] . map, я получаю очевидную ошибку типа, что карта не имеет типа [a] -> [[a]], как и ожидалось. Конечно, если я использую что-то вроде map (\x -> [x*5, x*6, x*7]) в качестве правильного аргумента для оператора композиции, все это работает.

Но было бы проблемой каждый раз указывать конкретную функцию; каким-то образом оператор >> = ведет себя более общим образом. Есть ли способ указать аргумент по типу? Например, могу ли я как-то рассказать о карте только для того, чтобы принимать в этом составе функции типа a -> [a]? Мне нужно написать функцию, которая имеет тип (a -> [a]) -> [a] -> [[a]] с нуля, потому что на самом деле нет способа сузить функцию карты до типа функции, которую я хочу?

Также, пожалуйста, не стесняйтесь сказать мне, что я приближаюсь к этому, все неправильно. Я до сих пор довольно новичок в этом типе вещей. Если это так, пожалуйста, укажите мне в правильном направлении.

ответ

7

Если проверить тип что-то вроде

> :t \f -> foldr (++) [] . map f 

в GHCi, как я сделал выше вы заметите что-то интересное

\f -> foldr (++) [] . map f :: (a -> [b]) -> [a] -> [b] 

Или, в погоню, то получается, что функция ввода fуже и естественно у есть более закрытый тип, о котором вы просили. Почему это так?

Давайте рассмотрим foldr (++) [], который более естественно под названием concat

concat :: [[a]] -> [a] 
concat = foldr (++) [] 

мы видим, что его вход должен быть, из списка списков. Если мы считаем, что это означает в контексте пост состава с map

concat   ::  [[c]] -> [c] 
     . map f :: [a] -> [ b ]   -- for (f :: a -> b) 

мы можем видеть, что b должны быть такими же, как [c] для некоторого типа c. Другими словами, информация об использовании результата отображения f, например. его прохождение через concat, имеет , течет назад, чтобы специализировать информацию, которую мы знаем про map и даже ее аргумент f.

Так, объединяющий b и [c] выше мы видим, что map должны быть немного более ограничительного типа

map ::* (a -> [c]) -> [a] -> [[c]] 

, где я пишу (::*), чтобы указать, что это специализация из map «s естественного типа осуществляется естественно, Объединение с типом concat.

+1

Черт, Хаскелл умный; умнее меня. Это странно. Спасибо, ответ принят. Это блестяще. –

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