Haskell Applicative [], почему я не могу заменить pure[] на [] в функции?

ghci> :t pure []
pure [] :: Applicative f => f [a]

ghci> pure []
[]

ghci> :t []
[] :: [a]

ghci> fmap ((:) 2) (pure [])
[2]

ghci> fmap ((:) 2) ([])
[]

Я бы подумал заменить pure[] с [] в fmap ((:) 2) (pure []) приведет к тому же результату.. кто может объяснить мне разницу?

2 ответа

Тип pure является Applicative f => a -> f a так pure []

имеет тип Applicative f => f [a], Вы можете указать f явно для разных аппликативных типов, например

pure [] :: Maybe [String]   //Just []
pure [] :: IO [String]      //displays '[]' in ghci
pure [] :: [[String]]       //[[]]

Тип fmap ((:) 2) (pure []) является (Applicative f, Num a) => f [a], Так как Ghci работает в монаде IO, которая является Applicativeвыбирает f быть IOи отображает полученный список [2] это то, что вы видите.

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

fmap ((:) 2) (pure []) :: (Maybe [Int])

который Just [2]

В fmap ((:) 2) ([]), нет элементов в списке ввода, поэтому вы получите пустой список.

С чего бы это было так же? Это разные выражения.

Возможно, это упрощает вещи, если мы просто посмотрим на списки. Итак, есть пустой список [], Его тип может быть любым, заключенным в квадратные скобки, в частности, вложенным списком:

Прелюдия> []:: [[Int]]
[]

Но есть и другой "пустой вложенный список":

Прелюдия> [[]]:: [[Int]]
[[]]

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

Prelude Control.Applicative> pure []:: [[Int]]
[[]]

Это, конечно, не то же самое, что пустой список,

Прелюдия> [[]] == []
Ложь

Особенно,

Прелюдия> (длина [], длина [[]])
(0,1)

А также fmapперебрасывать пустой список никогда ничего не делает, пока fmapПинг по пустому списку вызовет функцию с []: простой способ увидеть это

Prelude Control.Applicative> fmap undefined []
[]
Prelude Control.Applicative> fmap undefined [[]]
[* Исключение: Prelude.undefined

Действительно запутанная вещь в ваших испытаниях заключается в том, что ghci молча использует IO монада.


Есть также подкласс Applicative для фактической пустоты:

Prelude Control.Applicative>: i Альтернатива
Класс Applicative f => Альтернатива f где
пусто:: fa
(<‌ |>):: fa -> fa -> fa
некоторые:: f a -> f [a]
многие:: f a -> f [a]
- Определено в Control.Applicative
Экземпляр Alternative [] - определен в Control.Applicative
Экземпляр Альтернатива Возможно - Определено в Control.Applicative

Другие вопросы по тегам