首先要注意的是newtype
这里没有障碍——你可以参数化这些data
,然后你就有了一个普通的函子。喜欢
{-# LANGUAGE DeriveFunctor #-}
newtype WidthF a = Width { unWidth :: a } deriving (Show, Functor)
type Width = WidthF Int
不过,我不认为这是一个好主意。Width
不应该函子;在其中存储非数字类型是没有意义的。
user2407038 建议的一个选择是使其成为“单态函子”
import Data.MonoTraversable (MonoFunctor(..))
newtype Width = Width { unWidth :: Int } deriving (Show)
instance MonoFunctor Width where
omap f (Width w) = Width $ f w
这对我来说似乎也不明智——如果你将数字运算映射到一种通用方式,那么你不妨给Width
的实例Num
等并直接使用它们。但是,你几乎没有比简单的更好的类型系统保证
type Width = Int
可以很容易地修改没有任何帮助,另一方面是如果没有任何类型系统保护措施,它很容易被错误处理。
相反,我认为你想要的可能是这样的:
import Control.Lens
data Box = Box {
width, height :: Int }
widthInPx, heightInPx :: Lens' Box Int
widthInPx f (Box w h) = (`Box`h) <$> f w
heightInPx f (Box w h) = (Box w) <$> f h
然后你可以做
> Box 3 4 & widthInPx %~ (*2)
Box 6 4
> Box 4 2 & heightInPx %~ succ
Box 4 3