我想要一个12小时钟的单面图。
data Clock12Hours = Clock12Hours Int
deriving (Show)
instance Monoid Clock12Hours where
mappend (Clock12Hours x) (Clock12Hours y) = Clock12Hours $ (x + y) `mod` 12
mempty = Clock12Hours 12
当我mappend (Clock12Hours 4) (Clock12Hours 10)
时,我得到了正确的值- Clock12Hours 2
。
我的问题是:
fmap (id) Clock12Hours 10
的时候,我得到了Clock12Hours 10
。但是,如果我没有提供函子定义(如注释中所阐明的,甚至无法完成),那么它如何知道如何实现fmap呢?fmap (+1) (Clock12Hours 10)
时,我得到了一个错误No instance for (Num Clock12Hours) arising from a use of ‘+’
--为什么?fmap (+4) (Clock12Hours 10)
将返回Clock12Hours 2
。多么?发布于 2016-09-05 21:45:43
我觉得你想做这样的事:
{-# LANGUAGE Safe #-}
module Numeric.IntMod12 (
IntMod12(), lift1Enum, lift2Enum
) where
newtype IntMod12 = IntMod12 Int deriving (Eq, Ord, Show)
instance Enum IntMod12 where
{-# INLINABLE toEnum #-}
toEnum i = IntMod12 (mod i 12)
{-# INLINABLE fromEnum #-}
fromEnum (IntMod12 i) = i
lift1Enum :: (Enum a, Enum b) => (Int -> Int) -> a -> b
{-# INLINABLE lift1Enum #-}
lift1Enum f = \ x -> toEnum (f (fromEnum x))
lift2Enum :: (Enum a, Enum b, Enum c) => (Int -> Int -> Int) -> a -> b -> c
{-# INLINABLE lift2Enum #-}
lift2Enum f = \ x y -> toEnum (f (fromEnum x) (fromEnum y))
instance Real IntMod12 where
{-# INLINABLE toRational #-}
toRational (IntMod12 i) = toRational i
instance Num IntMod12 where
{-# INLINABLE fromInteger #-}
fromInteger i = IntMod12 (fromInteger (mod i 12))
(+) = lift2Enum (+)
(-) = lift2Enum (-)
(*) = lift2Enum (*)
negate = lift1Enum negate
abs = id
signum 0 = 0
signum _ = 1
instance Integral IntMod12 where
{-# INLINABLE toInteger #-}
toInteger (IntMod12 i) = toInteger i
div = lift2Enum div
mod = lift2Enum mod
quot = lift2Enum quot
rem = lift2Enum rem
divMod x y = (toEnum d, toEnum m) where
(d, m) = divMod (fromEnum x) (fromEnum y)
quotRem x y = (toEnum q, toEnum r) where
(q, r) = quotRem (fromEnum x) (fromEnum y)
instance Monoid IntMod12 where
mempty = 0
mappend = (+)
因为这不是Functor
(并且不能转换为Functor
),所以您必须使用类似lift1Enum
的东西而不是fmap
。
发布于 2016-09-05 20:31:20
我没有1.
的答案,因为我无法在GHC7.10.3上重现错误。
对于2.
:只有使用一个类型参数来构造的类型才能是函子,因为fmap
在其参数中是多态的,而Clock12Hours
不是。
要回答3.
:一个映射操作打开它的参数,应用一个函数并重新打包整个过程。使用这个定义,我们得出如下结论:
myMap :: (Int -> Int) -> Clock12Hours -> Clock12Hours
myMap f (Clock12Hours time) = Clock12Hours (f time)
但是现在我们遇到的问题是,我们可能没有12小时的时间,所以我们有两个选项: add 0 (mappend mempty
),或者编写normalize
函数:
normalize (Clock12Hours x) = Clock12Hours (x `mod` 12)
normalize clock = myMap (`mod` 12) clock
normalize = myMap (`mod` 12)
https://stackoverflow.com/questions/39336516
复制相似问题