在假设下,如何为(a,b)定义一个Log-instance,其中a,b已经是Log-instance?

时间:2019-06-23 14:49:29

标签: haskell

这是我们了解实例的功课,但是作为标题,我不知道“如何定义一个Log-instance(a,b),而a和b也是Log-instance”。

data FullLog = FullLog [String] deriving Show

instance Semigroup FullLog where
  FullLog a <> FullLog b = FullLog (a ++ b)

instance Monoid FullLog where
  mempty = FullLog []

instance Log FullLog where
  logMsg x = FullLog [x]

-- *Main> fib 3 :: (Int, ReverseLog)
-- (3,ReverseLog ["fib 3","fib 1","fib 2","fib 0","fib 1"])
-- instance Log ReverseLog where
data ReverseLog = ReverseLog [String] deriving Show

instance Semigroup ReverseLog where
  ReverseLog a <> ReverseLog b = ReverseLog (b ++ a)

instance Monoid ReverseLog where
  mempty = ReverseLog []

instance Log ReverseLog where
  logMsg x = ReverseLog [x]


-- *Main> fib 3 :: (Int, LastMsgLog)
-- (3,LastMsgLog (Just "fib 3"))
--instance Log LastMsgLog where
data LastMsgLog = LastMsgLog (Maybe String) deriving Show

instance Semigroup LastMsgLog where
  LastMsgLog a <> LastMsgLog b = LastMsgLog (b)

instance Monoid LastMsgLog where
  mempty = LastMsgLog (Nothing)

instance Log LastMsgLog where
  logMsg x = LastMsgLog (Just x)

-- *Main> fib 3 :: (Int, CountLog)
-- (3,CountLog 5)
--instance Log CountLog where
data CountLog = CountLog Int deriving Show

instance Semigroup CountLog where
  CountLog a <> CountLog b = CountLog (a+b)

instance Monoid CountLog where
  mempty = CountLog 0

instance Log CountLog where
  logMsg x = CountLog 1

我已经完成4个Log实例:FullLog,ReverseLog,LastMsgLog和CountLog, 现在,我需要定义Log-instance(a,b),其中a和b可以是FullLog,ReverseLog,LastMsgLog和CountLog中的任何一个。

我尝试直接定义Log (a,b),错误就像Not in scope: data constructor ‘Log’一样。

因此,我试图像上面一样定义类型MixLog

data MixLog = MixLog (a, b) deriving Show

instance MixLog :: (Log a, Log b) => Log (a, b) where
  Log ( a,  b) <> Log ( c,  d ) = Log (a <> c, b <> d)

而且还有error: parse error on input ‘::’

所以现在我很困惑,如何进行类型约束?

谢谢!

1 个答案:

答案 0 :(得分:2)

如果要将MixLog设为Log的实例,则可以这样实现:

data MixLog a b = MixLog (a, b)

instance (Log a, Log b) => Log (MixLog a b) where
  logMsg x = MixLog (logMsg x, logMsg x)

因此,您需要在a类型构造函数中指定类型参数bMixLog,此外,我们用logMsg :: Log c => String -> c对象定义MixLog函数,因此我们用2元组构造一个MixLog,其中两个元素都是logMsg x调用的结果(或者我们可以用不同的方式实现)。

不过,您可以省略MixLog数据构造函数,并将其实现为:

instance (Log a, Log b) => Log (a,b) where
  logMsg x = (logMsg x, logMsg x)

2元组没有什么特别的,因此我们可以使用其类型构造函数和数据构造函数。