首发于笔记
haskell中的设计模式:NewType

haskell中的设计模式:NewType

14 人赞同了该文章

为了让类型签名更加易懂,很多时候我们会用type为现有的类型起个别名

type Position = (Int,Int)

emm,一个在平面上的坐标,用2个整数表示,非常显然。但是如果不写类型标注,你就看不出二元组到底是Position还是用于其他用途的二元组

mkPos :: Int -> Int -> Position
mkPos x y = (x, y)
-- mkPos = (,)

这样呢?我们用抽象数据类型的方法,弄出一个构造子来,这样构造Position是很明显了。但是,还不够,这样的类型约束毕竟还是弱的,为了让这一切更加明确,我们使用newtype

newtype Position = Position (Int,Int)

以上,这是一个好方案,如果你忘记了显式调用Position,类型检查不会轻易放过你,假如你有需要复用(Int,Int),那newtype是避免混淆的好方法,举个例子,扫雷!


我们在一个9×9的Field上进行游戏,同时对每个格子,用Position类型表达它们的位置。同时,我们使用一个非常简单的方法放置地雷,任取一个随机数并且取n的模,余数会严格限 定在[0, n)之间。同时随机数本身也可用很简单的方式解决,一个方程和一个初始种子,再加上状态就行了。

newtype State = State (Int,Int)

我承认System.Random和State Monad的存在使得我举的例子有点傻气,但是我也不是一个特别聪明的人,而且我真的这样做。总之newtype的封装使得同一类型可以安全地用于不同概 念的抽象,并且,newtype定义的“新类型”实际上在运行时没有多余成本。该是二元组的还是二元组。


更“好”的例子:Data.Monoid模块中的Sum和Product类型


Data.Coerce


原文:GHC/Coercible - HaskellWiki


给出一个NewType定义

newtype HTML = MkHTML String

-- 在HTML类型和String之间的转换非常简单。

toHTML :: String -> HTML
toHTML s = MkHTML s

fromHTML :: HTML -> String
fromHTML (MkHTML s) = s

-- 这两个函数都是没有运行时负担的。

-- 但是要如何转换出一整个列表的HTML呢? 我们可以试着写出转换函数

toHTMLs :: [String] -> [HTML]
toHTMLs = map MkHTML


-- 不妙了,虽然MkHTML啥都没干,但是map对原list的遍历和重建副本是有代价的。

-- 解决方案是GHC7.8.1引入的Coercible

import Data.Coerce
toHTMLs :: [String] -> [HTML]
toHTMLs = coerce

-- 这是GHC留下的一个类型系统上的后门,由GHC本身实现,但是妙处在于,虽然它hack了类型系统,但是它的类型转换是安全的。

-- 论文:http://research.microsoft.com/en-us/um/people/simonpj/papers/ext-f/coercible.pdf

-- 太长不看版:

-- newtype定义的封装可以与原类型任意使用coerce转换,无运行时成本。(但是,这里没有讨论带类型参数的情况)

-- 对于使用了所谓“Phantom Type”的newtype定 义,coerce也能识别

newtype NT a = MkNT ()

trans :: NT Bool -> NT Int
trans = coerce

-- 对于藏在其他结构内部的newtype定义,当然 也没问题。

newtype Age = MkAge Int
newtype AgeRange = MkAR (Int,Int)
newtype BigAg
编辑于 2021-03-20 02:59
写下你的评论...

5 条评论
默认
最新
谭九鼎
不懂newtype与data的关系,什么时候用newtype,为什么newtype只允许一个参数的构造函数
2021-10-15
瞎想符式
暂时不用吧,也没有什么事情,newtype是additional的。
2021-10-15
祖与占

用 haskell-hvr/newtype 还挺方便的

2021-03-20
祖与占

还有 Control.Lens.Wrapped

2021-03-20
瞎想符式
谢谢谢谢! 这就去看(
2021-03-20

文章被以下专栏收录

想来知乎工作?请发送邮件到 jobs@zhihu.com
登录即可查看 超5亿 专业优质内容
超 5 千万创作者的优质提问、专业回答、深度文章和精彩视频尽在知乎。