首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >强型(新型)广义

强型(新型)广义
EN

Stack Overflow用户
提问于 2020-03-24 21:09:49
回答 2查看 97关注 0票数 1

我正在尝试实现“强类型”,即携带更多信息的新类型,如下面的代码片段所示

代码语言:javascript
复制
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE MultiParamTypeClasses #-}

class UnderlyingTypeable a  b where 
 get :: a -> b

newtype Voltage = Voltage Double deriving (Show,Read,Num, Eq,Ord)
instance UnderlyingTypeable Voltage Double where
 get(Voltage v) = v

newtype Resistance = Resistance Double deriving (Show,Read,Num, Eq,Ord)
instance UnderlyingTypeable Resistance Double where
 get(Resistance r) = r

newtype Ampere = Ampere Double deriving (Show,Read,Num, Eq,Ord)
instance UnderlyingTypeable Ampere Double where
 get(Ampere a) = a


v1 = Voltage 15
v2 = Voltage 21
--works nicely. 
sum = v1 + v2

r = Resistance 10

-- does not compile. Great.
--foo = v1/r  

--Works ok. We got "strong type" that prevent adding cabbage and carot unless explicitly said..
i = Ampere $ (get v1) / (get r)

一切正常。并且可以使用不同的基础类型。

现在我要努力概括一下:

如何定义get函数的“默认”实现?(以避免非常重复和枯燥的显式实例)

第二个问题(更理论性的)。我确实花了一些时间才发现我需要激活{-# LANGUAGE MultiParamTypeClasses #-}才能使类型类声明确定。是否有可安全激活的语言扩展列表?-安全地说,我的意思是它们不应该破坏代码,不使用它,它们不应该自己重叠。

EN

回答 2

Stack Overflow用户

发布于 2020-03-25 01:17:24

正如@chi在一条评论中指出的那样,GHC使用来自coerceData.Coerce函数,有一个“安全强制性”的概念。实际的规则有点复杂,但简化了一些,可以使用coerce在具有相同表示形式的两种类型之间进行转换,并且每个newtype具有与其底层类型相同的表示形式,因此可以安全地强制使用其基础类型(或从其底层类型):

代码语言:javascript
复制
i = Ampere $ coerce v1 / coerce r

考虑到这一点,您甚至可能不需要您的UnderlyingTypeable类,并且可以直接使用coerce。但是,如果您仍然需要它,那么下面的内容应该提供一个合理的缺省值:

代码语言:javascript
复制
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE DefaultSignatures #-}

import Data.Coerce

class UnderlyingTypeable a  b where 
 get :: a -> b
 default get :: Coercible a b => a -> b
 get = coerce

为了回答你的第二个问题,FP Complete ( Stack的制造者等)提供了一份推荐的扩展列表,作为他们的RIO项目的一部分。见自述文件。他们之所以被选中,是因为他们被Haskell社区所接受,不太可能破坏任何东西,而且通常被认为是安全的。

票数 3
EN

Stack Overflow用户

发布于 2020-03-25 13:46:54

有许多包,如新型仿制药矫顽力透镜 ( Control.Lens.Wrapped模块),它们提供了一个api,用于处理新类型、统一包装器和解包器等特性。

例如,使用来自强制-utils的unpack

代码语言:javascript
复制
{-# LANGUAGE DeriveGeneric #-}
import CoercibleUtils.Newtype
import GHC.Generics

newtype Voltage = Voltage Double deriving (Show,Read,Eq,Ord,Generic)

newtype Resistance = Resistance Double deriving (Show,Read,Eq,Ord,Generic)

i = Ampere $ unpack v1 / unpack r

unpack有一个Newtype约束。根据文件:

此模块导出的Newtype类的版本有一个实例,用于所有新类型,其泛型实例生成的强制实例是可见的。用户不需要也可能不应该编写自己的实例。

因此,似乎为我们的新类型派生Generic就足够了,并确保构造函数在作用域中(对于Coercible实例)。

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

https://stackoverflow.com/questions/60839394

复制
相关文章

相似问题

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