Function from `mappend` function for instance of` Monoid`?

I have a data structure (this is a special subclass of rosewood that forms a lattice with functions with the smallest lower bound and with the smallest upper bound) and it supports two perfectly reasonable functions that serve as the Monoid t21> class.

Is there a way to support anonymous Monoid instances in haskell? Is this an instance where I should use something like Template-Haskell to create my classes for me?

I would like makeMonoid :: (RT a -> RT a -> RT a) -> Monoid a to let me instantiate on the fly, but I understand that this is not compatible with the stock type system, as I understand it. I am fine if I just need to select the default merge function and write newtype for other merges, just curious

+2
source share
1 answer

You can create "local" instances of Monoid on the fly using the tools in the reflection package. There is a ready-made example in the repository. This answer explains this a bit.

This is the newtype wrapper over values ​​of type a , on which we will define our Monoid instance.

 newtype M as = M { runM :: a } deriving (Eq,Ord) 

Note that there is a phantom s type that does not appear on the right side. It will carry additional information necessary for the operation of the local Monoid instance.

This is a record whose fields represent two operations of the Monoid class:

 data Monoid_ a = Monoid_ { mappend_ :: a -> a -> a, mempty_ :: a } 

The following is a Monoid instance Monoid for M :

 instance Reifies s (Monoid_ a) => Monoid (M as) where mappend ab = M $ mappend_ (reflect a) (runM a) (runM b) mempty = a where a = M $ mempty_ (reflect a) 

It says: "whenever s is a level-level representation of our Monoid Monoid_ dictionary, we can flip it to get the dictionary and use the fields to implement Monoid operations for M ".

Please note that the actual value of a passed to reflect is not used, it is transmitted only as a “proxy” of type M as , which tells reflect which type ( s ) to use to “return the record”.

The actual local instance is created using the reify function:

 withMonoid :: (a -> a -> a) -> a -> (forall s. Reifies s (Monoid_ a) => M as) -> a withMonoid fzv = reify (Monoid_ fz) (runM . asProxyOf v) asProxyOf :: fs -> Proxy s -> fs asProxyOf a _ = a 

The asProxyOf function is a trick to convince the compiler that the phantom type used in the monoid is the same as the Proxy specified in reify .

+2
source

Source: https://habr.com/ru/post/986867/


All Articles