首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在‘`newtype’上使用‘a’的函数

在‘`newtype’上使用‘a’的函数
EN

Stack Overflow用户
提问于 2014-10-06 02:35:38
回答 5查看 211关注 0票数 9

假设我有下面的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而不是这样做:

代码语言:javascript
复制
addFoo :: Foo -> Foo -> Foo
addFoo (Foo x) (Foo y) = Foo $ x + y
EN

回答 5

Stack Overflow用户

回答已采纳

发布于 2014-10-06 03:10:32

正如haskell98知道如何为您派生这些EqShow实例一样,您也可以打开ghc的GeneralizedNewtypeDeriving扩展来获取所需的NumOrd实例:

代码语言:javascript
复制
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
票数 12
EN

Stack Overflow用户

发布于 2014-10-06 03:43:40

您希望将Integer -> Integer -> Integer类型的函数提升到Foo -> Foo -> Foo。为此,您可以定义实用程序函数:

代码语言:javascript
复制
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

然后,您可以使用它如下:

代码语言:javascript
复制
liftFoo2 (+) (Foo 10) (Foo 5)

liftFoo2 max (Foo 10) (Foo 5)

这具有不需要扩展的优点。

另一个选项是使Foo新类型的定义更加允许,这样您就可以使它成为FunctorApplicative的一个实例。

代码语言:javascript
复制
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

现在,您可以执行以下操作:

代码语言:javascript
复制
(+) <$> foo 10 <*> foo 5

max <$> foo 10 <*> foo 5

因为foo是专门针对Integer类型的,所以不会丢失类型检查的任何好处。

票数 11
EN

Stack Overflow用户

发布于 2014-10-06 08:24:32

你也可以使用安全的矫顽力。粗略地说,您可以使用Data.Coerce.coerce自动包装/解封新类型。

代码语言:javascript
复制
> 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 )则不那么有效,因为在后一种情况下,需要一个类型注释。

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/26209354

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档