Как/может ли этот тип быть превращен в Моноидный экземпляр


У меня есть тип данных:

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 5

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. В статье, которую я связал, эта идиома обсуждается более подробно.