假设我有下面的newtype
newtype Foo = Foo Integer deriving (Eq, Show)
是否有一种简洁的方法可以添加两个Foo的:
(Foo 10) + (Foo 5) == Foo 15
或者得到最大值:
max (Foo 10) (Foo 5) == Foo 5
我很好奇,是否可以轻松地将a的函数用于newtype a而不是这样做:
addFoo :: Foo -> Foo -> Foo
addFoo (Foo x) (Foo y) = Foo $ x + y发布于 2014-10-06 03:10:32
正如haskell98知道如何为您派生这些Eq和Show实例一样,您也可以打开ghc的GeneralizedNewtypeDeriving扩展来获取所需的Num和Ord实例:
Prelude> :set -XGeneralizedNewtypeDeriving
Prelude> newtype Foo = Foo Integer deriving (Eq, Show, Num, Ord)
Prelude> (Foo 10) + (Foo 5) == Foo 15
True
Prelude> max (Foo 10) (Foo 5) == Foo 5
False发布于 2014-10-06 03:43:40
您希望将Integer -> Integer -> Integer类型的函数提升到Foo -> Foo -> Foo。为此,您可以定义实用程序函数:
liftFoo :: (Integer -> Integer) -> Foo -> Foo
liftFoo f (Foo a) = Foo $ f a
liftFoo2 :: (Integer -> Integer -> Integer) -> Foo -> Foo -> Foo
liftFoo2 f (Foo a) (Foo b) = Foo $ f a b
-- and so on然后,您可以使用它如下:
liftFoo2 (+) (Foo 10) (Foo 5)
liftFoo2 max (Foo 10) (Foo 5)这具有不需要扩展的优点。
另一个选项是使Foo新类型的定义更加允许,这样您就可以使它成为Functor和Applicative的一个实例。
import Control.Applicative
newtype Foo a = Foo a deriving (Eq, Show)
foo :: Integer -> Foo Integer
foo = Foo
instance Functor Foo where
fmap f (Foo a) = Foo $ f a
instance Applicative Foo where
pure = Foo
(Foo f) <*> (Foo a) = Foo $ f a现在,您可以执行以下操作:
(+) <$> foo 10 <*> foo 5
max <$> foo 10 <*> foo 5因为foo是专门针对Integer类型的,所以不会丢失类型检查的任何好处。
发布于 2014-10-06 08:24:32
你也可以使用安全的矫顽力。粗略地说,您可以使用Data.Coerce.coerce自动包装/解封新类型。
> import Data.Coerce
> newtype Foo = Foo Integer deriving (Eq, Show, Ord)
> coerce (Foo 1) :: Integer
1
> let f :: Integer -> Integer ; f x = x + 1
> coerce f (Foo 10)
Foo 11
> coerce (succ :: Integer -> Integer) (Foo 10) :: Foo
Foo 11
> coerce (max :: Integer -> Integer -> Integer) (Foo 10) (Foo 5) :: Foo
Foo 10请注意,它对f这样的单形函数非常有效,但对于多态函数(如succ )则不那么有效,因为在后一种情况下,需要一个类型注释。
https://stackoverflow.com/questions/26209354
复制相似问题