gpt4 book ai didi

haskell - 即使您无法对新类型进行模式匹配,新类型也不会产生任何成本吗?

转载 作者:行者123 更新时间:2023-12-02 18:10:43 26 4
gpt4 key购买 nike

上下文

我知道的大多数 Haskell 教程(例如 LYAH )都将新类型作为一种免费的习惯用法引入,可以增强类型安全性。例如,此代码将进行类型检查:

type Speed = Double
type Length = Double

computeTime :: Speed -> Length -> Double
computeTime v l = l / v

但这不会:

newtype Speed = Speed { getSpeed :: Double }
newtype Length = Length { getLength :: Double }

-- wrong!
computeTime :: Speed -> Length -> Double
computeTime v l = l / v

这将:

-- right
computeTime :: Speed -> Length -> Double
computeTime (Speed v) (Length l) = l / v

在此特定示例中,编译器知道 Speed 只是一个 Double,因此模式匹配没有实际意义,不会生成任何可执行代码。

问题

当新类型作为参数类型的参数出现时,它们仍然是免费的吗?例如,考虑一个新类型列表:

computeTimes :: [Speed] -> Length -> [Double]
computeTimes vs l = map (\v -> getSpeed v / l) vs

我还可以对 lambda 中的速度进行模式匹配:

computeTimes' :: [Speed] -> Length -> [Double]
computeTimes' vs l = map (\(Speed v) -> v / l) vs

无论哪种情况,出于某种原因,我觉得真正的工作已经完成!当新类型被埋在嵌套参数数据类型的深层树中时,我开始感到更加不舒服,例如 map 速度[设置速度];在这种情况下,可能很难或不可能对新类型进行模式匹配,并且必须求助于像 getSpeed 这样的访问器。

TL;DR

即使新类型作为另一个参数类型的(可能深埋的)参数出现,使用新类型永远不会会产生成本吗?

最佳答案

新类型本身是免费的。应用它们的构造函数或对其进行模式匹配的成本为零。

当用作其他类型的参数时,例如[T] 如果 T,则 [T] 的表示与 [T'] 的表示完全相同> 是 T'newtype。因此,性能没有损失。

但是,我可以看到两个主要警告。

newtype 和实例

首先,newtype 经常用于引入类型类的新实例。显然,当这些是用户定义的时,无法保证它们与原始实例具有相同的成本。例如,当使用

newtype Op a = Op a
instance Ord a => Ord (Op a) where
compare (Op x) (Op y) = compare y x

比较两个 Op Int 的成本比比较 Int 的成本稍高,因为需要交换参数。 (我在这里忽略了优化,这可能会使它们在触发时免费。)

newtypes 用作类型参数

第二点更加微妙。考虑以下两种标识 [Int] -> [Int]

的实现
id1, id2 :: [Int] -> [Int]
id1 xs = xs
id2 xs = map (\x->x) xs

第一个具有恒定成本。第二个具有线性成本(假设没有优化触发器)。聪明的程序员应该更喜欢第一种实现,因为它也更容易编写。

假设现在我们仅在参数类型上引入 newtypes:

id1, id2 :: [Op Int] -> [Int]
id1 xs = xs -- error!
id2 xs = map (\(Op x)->x) xs

由于类型错误,我们无法再使用恒定成本实现。线性成本实现仍然有效,并且是唯一的选择。

现在,这非常糟糕。 [Op Int] 的输入表示与 [Int] 完全相同。然而,类型系统禁止我们以有效的方式执行身份!

为了解决这个问题,safe coercions在 Haskell 中引入。

id3 :: [Op Int] -> [Int]
id3 = coerce

神奇的coerce函数,在某些假设下,会根据需要删除或插入newtype以使类型匹配,甚至其他类型中,与上面的[Op Int]一样。此外,它是一个零成本函数。

请注意,强制仅在某些条件下起作用(编译器会检查它们)。其中之一是 newtype 构造函数必须可见:如果模块未导出 Op::a -> Op a,则无法强制 Op IntInt 或反之亦然。事实上,如果模块导出类型但不导出构造函数,那么无论如何通过强制访问构造函数都是错误的。这使得“智能构造函数”惯用语仍然安全:模块仍然可以通过不透明类型强制执行复杂的不变量。

关于haskell - 即使您无法对新类型进行模式匹配,新类型也不会产生任何成本吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42764432/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com