Как/может ли этот тип быть превращен в Моноидный экземпляр
У меня есть тип данных:
data Stuff s = Stuff { name :: s, idx :: Int }
И хотим превратить это в моноид со следующими реализациями:
tmappend :: Stuff s -> Stuff t -> Stuff (s,t)
tmappend s1 s2 = Stuff (name s1, name s2) (idx s1 + idx s2)
tzero :: Stuff ()
tzero = Stuff () 0
Обратите внимание, что можно получить произвольно вложенные кортежи через mconcat
.
Но tmappend в настоящее время нарушает сигнатуру типа mappend
. Это действительно моноид? Можно ли сделать его единым с лучшим представлением типа.
1 ответ:
Это известно как слабый моноидальный функтор. Я настоятельно рекомендую вам прочитать эту статью , в которой показано, как Аппликативы являются одним из типов слабых моноидов, и вы можете переформулировать свой тип как
Applicative
и получить эквивалентный интерфейс:Обратите внимание, чтоinstance Applicative Stuff where pure a = Stuff a 0 (Stuff f m) <*> (Stuff x n) = Stuff (f x) (m + n) tmappend :: (Applicative f) => f a -> f b -> f (a, b) tmappend fa fb = (,) <$> fa <*> fb tzero :: (Applicative f) => f () tzero = pure ()
tmappend
иtzero
работают для всехApplicative
s, а не только дляStuff
. В статье, которую я связал, эта идиома обсуждается более подробно.