Как вы заметили, вы не можете предоставить instance Monoid (Response a)
, потому что вы не можете определить mempty :: Response a
. Почему бы и нет? Итак, mempty
должен иметь тип Response a
для всех a
, включая, скажем, Bool
. Но вы не можете создать значение типа Response Bool
, только Response (HashMap Text (Sum Int))
и Response (Sum Int)
. Таким образом, вы не сможете создать файл mempty
. Это не проблема для mappend
, потому что вам получили Response a
, так что вы можете проверить, какой a
вам дали. Но mempty
нечего анализировать.
Так что ты можешь сделать? Ну, во-первых, вы можете предоставить instance Semigroup (Response a)
. Полугруппа — это именно моноид без mempty
, так что это именно то, что вам нужно. Начиная с GHC 8, вы можете найти этот класс типов в пакете base
, в модуле Data.Semigroup
; до этого вам нужно использовать пакет semigroups
с тем же именем модуля. Вместо mappend
используется бинарный оператор (<>)
. Так что у вас будет
import Data.Semigroup
import Data.Monoid hiding ((<>))
-- ...
instance Semigroup (Response a) where
ResponseMap v1 <> ResponseMap v2 = ResponseMap $ v1 <> v2
ResponseSum v1 <> ResponseSum v2 = ResponseSum $ v1 <> v2
Вы также можете предоставить конкретные Monoid
экземпляры для индексов типов, которые вы можете построить. С FlexibleInstances
это выглядит так
{-# LANGUAGE FlexibleInstances #-}
instance Monoid (Response (HashMap Text (Sum Int))) where
mempty = ResponseMap mempty
mappend = (<>)
instance Monoid (Response (Sum Int)) where
mempty = ResponseSum mempty
mappend = (<>)
Теперь, для случаев, когда вы действительно знаете, что такое единица измерения, у вас есть экземпляр Monoid
.
person
Antal Spector-Zabusky
schedule
08.09.2016
newtype Response a = Response a
, но не так полезно, потому чтоa
может быть толькоSum Int
илиHashMap Text (Sum Int)
. Если вы используетеnewtype
, вы можете использоватьGeneralizedNewtypeDeriving
, чтобы получить экземплярMonoid
бесплатно. - person Benjamin Hodgson♦   schedule 08.09.2016Response a
как новый тип, был бы у меня способ определить над ним функцию, которая знает, с чемa
она работает? - person ppb   schedule 09.09.2016f :: Response (Sum Int) -> Foo
- person Benjamin Hodgson♦   schedule 09.09.2016