Haskell 在fmap时防止自定义类型内的错误值
我想要一个12小时时钟的幺半群Haskell 在fmap时防止自定义类型内的错误值,haskell,Haskell,我想要一个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(时钟12小时4)(时钟12小时10)时,我
data Clock12Hours = Clock12Hours Int
deriving (Show)
instance Monoid Clock12Hours where
mappend (Clock12Hours x) (Clock12Hours y) = Clock12Hours $ (x + y) `mod` 12
mempty = Clock12Hours 12
当我mappend(时钟12小时4)(时钟12小时10)
时,我得到了正确的值-clock12小时2
我的问题是:
fmap(id)时钟12小时10
时,我得到时钟12小时10
。但是,如果我没有提供函子定义(如评论中所阐明的,甚至无法定义),它怎么知道如何fmap呢fmap(+1)(时钟12小时10)
时,我得到一个错误没有使用“+”引起的(Num clock12小时)的实例
-为什么fmap(+4)(clock12hours10)
将返回clock12hours2
。如何我没有回答
1.
,因为我无法在GHC 7.10.3上重现错误
对于2.
:只有使用1个类型参数构造的类型才能是函子,因为fmap
的参数是多态的,而Clock12Hours
的参数不是多态的
回答3.
:映射操作解压其参数,应用函数并重新打包整个内容。使用此定义,我们得出:
myMap :: (Int -> Int) -> Clock12Hours -> Clock12Hours
myMap f (Clock12Hours time) = Clock12Hours (f time)
但现在的问题是,我们可能无法获得12小时的时间,因此我们有两个选项:添加0(mappend mempty
),或编写一个normalize
函数:
normalize (Clock12Hours x) = Clock12Hours (x `mod` 12)
normalize clock = myMap (`mod` 12) clock
normalize = myMap (`mod` 12)
我没有回答
1.
,因为我无法在GHC 7.10.3上重现错误
对于2.
:只有使用1个类型参数构造的类型才能是函子,因为fmap
的参数是多态的,而Clock12Hours
的参数不是多态的
回答3.
:映射操作解压其参数,应用函数并重新打包整个内容。使用此定义,我们得出:
myMap :: (Int -> Int) -> Clock12Hours -> Clock12Hours
myMap f (Clock12Hours time) = Clock12Hours (f time)
但现在的问题是,我们可能无法获得12小时的时间,因此我们有两个选项:添加0(mappend mempty
),或编写一个normalize
函数:
normalize (Clock12Hours x) = Clock12Hours (x `mod` 12)
normalize clock = myMap (`mod` 12) clock
normalize = myMap (`mod` 12)
我想你是想做这样的事:
{-# 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 = (+)
因为这不是一个
函子
(并且不能变成函子
),所以您必须使用类似lift1Enum
的东西,而不是fmap
,我想您的意思是这样做的:
{-# 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 = (+)
因为这不是
函子
(并且不能转换为函子
),您必须使用类似于lift1Enum
的内容,而不是fmap
此类型不是函子,不能成为函子。函子必须是具有1个参数的类型构造函数。GHC版本7.10.3在fmap id(时钟12小时10小时)上抛出错误
。这三个问题毫无意义:你没有也不可能有一个函子,所以我不相信你声称的#1和#2的结果。问题3,忽略函子问题,只需要一个Num
实例,比如Clock12Hours
,因为(+4)::Num a=>a->a
@amitaibu再次检查fmap id>(Clock12Hours 10)
。在我们看来,它不可能产生任何结果。可能,发布完整的代码和GHCi会话。可能,某些内容的定义与上面发布的内容不同。@amitaibu:函数应用程序在Haskell中是左关联的,因此代码的意思是(fmap id Clock12Hours)12
。这“有效”由于Clock12Hours
数据构造函数的作用类似于一个函数,因此您的代码使用实例函子((->)r
(请参阅)。我想您的意思是编写fmap id(Clock12Hours 12)
,因为(Clock12Hours 12)无法工作
不是任何类型的函子
。此类型不是函子,不能成为函子。函子必须是带1个参数的类型构造函数。GHC 7.10.3版在fmap id(时钟12小时10小时)上抛出错误
。这三个问题毫无意义:你没有也不可能有一个函子,所以我不相信你声称的#1和#2的结果。问题3,忽略函子问题,只需要一个Num
实例,比如Clock12Hours
,因为(+4)::Num a=>a->a
@amitaibu再次检查fmap id>(Clock12Hours 10)
。在我们看来,它不可能产生任何结果。可能,发布完整的代码和GHCi会话。可能,某些内容的定义与上面发布的内容不同。@amitaibu:函数应用程序在Haskell中是左关联的,因此代码的意思是(fmap id Clock12Hours)12
。这“有效”由于Clock12Hours
数据构造函数的作用类似于一个函数,因此您的代码使用实例函子((->)r
(请参阅)。我想您的意思是编写fmap id(Clock12Hours 12)
,因为(Clock12Hours 12)无法工作
不是任何类型的Functor
。因此,在您的安装中,fmap id
根本不起作用?(这对我来说更有意义,因为我不明白它在我的上是如何工作的)。我似乎也有v7.10.3。我可以将数据
更改为其他内容以满足我的需要,但仍然只有Int参数吗(即,data Clock12Hours a=Clock12Hours a
不会将其仅限于Int
)太长了,读不下去了,你可以做,虽然这会破坏你的数据类型的目的,不是吗?你不能让你的类型多态,然后限制它,这是荒谬的。同样,这是已经存在于Haskell。TL;Dr不这样做。所以,在安装时,<代码> FMAP ID <代码>根本不起作用?(这对我来说更有意义,因为我不明白它在我的上是如何工作的)。我似乎也有v7.10.3。我可以将数据
更改为其他内容以满足我的需要,但仍然只有Int参数(即数据时钟12hours a=时钟12hours a
不会将其限制为Int
仅)?