deniok: (Default)
deniok ([personal profile] deniok) wrote2013-04-03 02:20 pm

А вот кому трехпараметрических типов



К завтрашнему занятию задачку со звёздочкой сделал, а то некоторые больно умные последние 15 минут практики бьют баклуши, решив всё заданное.

Введём следующий трёхпараметрический типовый оператор, инкапсулирующий композицию однопараметрических конструкторов типов:
newtype Compose f g x = Compose {getCompose :: f (g x)}
Каков кайнд этого конструктора типов? Приведите пример замкнутого типа, сконструированного с помощью Compose, и пример терма этого типа.

Определите функцию
ffmap h = getCompose . fmap h . Compose
и объясните её выведенный тип. Попробуйте осуществить вызов
> ffmap (+42) $ Just [1,2,3]
В чём причина ошибки?

Чтобы обеспечить работоспособность подобного вызова, сделайте тип Compose представителем класса типов Functor:
instance (Functor f, Functor g) => Functor (Compose f g) where
  fmap                =   ???
Проверьте работоспособность на примерах:
> ffmap (+42) $ Just [1,2,3]
Just [43,44,45]
> ffmap (+42) $ [Just 1,Just 2,Nothing]
[Just 43,Just 44,Nothing]


Сделайте тип Compose представителем класса типов Applicative:
instance (Applicative f, Applicative g) => Applicative (Compose f g) where
  pure               = ???
  (<*>)              = ???
Проверьте работоспособность на примерах:
> getCompose $ (+) <$> Compose [Just 1,Just 2] <*> Compose [Nothing,Just 40]
[Nothing,Just 41,Nothing,Just 42]
> getCompose $ (+) <$> Compose [Just 1,Just 2] <*> Compose [Just 30,Just 40]
[Just 31,Just 41,Just 32,Just 42]
> getCompose $ Compose [[(+1)],[(+2),(+3)]] <*> Compose [[10,20],[]]
[[11,21],[],[12,22,13,23],[]]


[personal profile] lebedev 2013-04-03 02:13 pm (UTC)(link)
А последний пункт точно можно без Monad сделать?

[personal profile] lebedev 2013-04-03 02:28 pm (UTC)(link)
Ох как тут всё красиво получается:

Compose f <*> Compose x = Compose $ liftA2 (<*>) f x

так ведь?

[identity profile] migmit.livejournal.com 2013-04-03 01:32 pm (UTC)(link)
Я для таких вещей обычно использую TypeCompose.

[identity profile] deni-ok.livejournal.com 2013-04-03 01:54 pm (UTC)(link)
Мне там нравится имя unOO в
newtype OO f j a b = OO { unOO :: f (a `j` b) }

[identity profile] udpn.livejournal.com 2013-04-03 05:35 pm (UTC)(link)
А почему без доказательств?

[identity profile] deni-ok.livejournal.com 2013-04-03 05:40 pm (UTC)(link)
По просьбам трудящихся дополнительное задание: докажите, что реализованные вами представители удовлетворяют всем законам соответствующих классов типов.

[identity profile] udpn.livejournal.com 2013-04-05 03:07 pm (UTC)(link)
Ура-а-а! Спасибо.

[identity profile] sassa-nf.livejournal.com 2013-04-03 06:17 pm (UTC)(link)
"(<*>) = ???"

а вы студиков "pointless" функции требуете сочинять?

[identity profile] deni-ok.livejournal.com 2013-04-03 06:29 pm (UTC)(link)
Нет, не требую, они сами предпочитают. Там место оставлено перед =, чтобы фломастером на доске, куда это проектируется, образцы писать :)

[identity profile] sassa-nf.livejournal.com 2013-04-03 07:02 pm (UTC)(link)
ага, значит, не 9*2 :)

pure = Compose . pure . pure -- красиво
fmap = (Compose .) . (. getCompose) . fmap . fmap -- ой...
(<*>) = (Compose .) . (. getCompose) . (<*>) . ((pure (<*>)) <*>) . getCompose -- выдыхай, бобёр!

[identity profile] deni-ok.livejournal.com 2013-04-03 07:06 pm (UTC)(link)
Как мне подсказывают студенты в http://deniok.dreamwidth.org/50419.html здесь был бы уместен liftA2.

[identity profile] sassa-nf.livejournal.com 2013-04-03 07:16 pm (UTC)(link)
мдя. хорошо. я с развёрнутого варианта начинал - т.е. вместо liftA2 было (pure (<*>)) <*> f <*> x

Тут забавно, что в Хаскеле навыворот требование - class Functor a => Applicative a, хотя нужно было бы наоборот, instance Applicative a => Functor a where fmap = (<*>) . pure

[identity profile] deni-ok.livejournal.com 2013-04-03 07:40 pm (UTC)(link)
Не уверен, что понял мысль последнего абзаца. Applicative в Хаскелле близок, насколько я помню МакБрайда-Патерсона, к lax monoidal functor из ТК. Ну и технически он, конечно, является частным случаем "более бедного" класса типов - функтора.

[identity profile] sassa-nf.livejournal.com 2013-04-03 07:52 pm (UTC)(link)
Я хочу сказать, что в Хаскелле изначально требуется наличие fmap, а потом в комментариях требуется соответствие pure, <*> и fmap.

Хотя на самом деле можно бы вывести fmap в обратную сторону - из наличия pure и <*>. В частности, в данном случае из апликативности Compose следовала бы его функториальность (хотя и с другими ограничениями на типы f и g).

[identity profile] deni-ok.livejournal.com 2013-04-03 08:54 pm (UTC)(link)
Я бы всё-таки рассматривал pure и <*> как некоторое расщепление fmap. Для "сложных" структур (например, списков) такое расщепление можно сделать несколькими способами.

При этом идея получения Functor из Applicative становится похожей на следующую: если у нас у элементов есть обратные, давайте определим единицу как A*A^{-1}, и уже отсюда будем выводить другие её свойства :)

[identity profile] sassa-nf.livejournal.com 2013-04-03 09:10 pm (UTC)(link)
ну, вобще-то, да. Раз уж всякий Applicative является функтором, то можно и дописать, что он таки Functor и написать ему тот самый fmap.

Про расщепление разными способами, ага, у МакБрайда и Патерсона было.