Haskell 几何点数据类型-元组与记录?
我可以想出三种方法在Haskell中将几何点定义为代数数据类型。我想将其定义为代数数据类型,以便更好地编写文档 作为元组类型:Haskell 几何点数据类型-元组与记录?,haskell,Haskell,我可以想出三种方法在Haskell中将几何点定义为代数数据类型。我想将其定义为代数数据类型,以便更好地编写文档 作为元组类型: data Point a = Point a a 作为元组: data Point a= Point (a,a) 作为记录: data Point a = Point { pointx :: a, pointy :: a} 哪种设计/风格更好?为什么?在哈斯克尔,唱片是一个有争议的话题。社会上有一个共识,即由于许多原因,现有的实施并不理想,目前正在采取措施解决这一
data Point a = Point a a
作为元组:
data Point a= Point (a,a)
作为记录:
data Point a = Point { pointx :: a, pointy :: a}
哪种设计/风格更好?为什么?在哈斯克尔,唱片是一个有争议的话题。社会上有一个共识,即由于许多原因,现有的实施并不理想,目前正在采取措施解决这一问题 现在,由于现有的记录实现是次优的,许多Haskeller倾向于从不使用它们。我就是其中之一 我建议采取以下措施:
{-# LANGUAGE DeriveFoldable, DeriveFunctor, DeriveTraversable #-}
data Point a =
Point !a !a
deriving (Functor, Foldable, Traversable)
这将为您提供一些标准类的免费实例,而严格的数据结构是推荐的默认值。根据我的说法,更难的是tuple,因为很难在tuple中创建任何更改。最好的是最后一个。我认为这主要取决于您手头的用例 虽然我从不使用data
Point=Point(a,a)
,因为这引入了一层间接寻址,它通过两个机器字膨胀了数据结构,一个用于点,另一个用于指向其中元组的指针
最好使用type Point a=(a,a)
这只是一个别名,或者newtype Point a=Point(a,a)
这会在编译时得到优化,所以在这种情况下您会得到好处
最灵活的(对于flexible的一些定义)是最后一种方法,尽管我将记录pr1
和pr2
称为“投影到第一个/第二个组件”。这种方法也很适合使用镜头
正如@nikitavolkov所说的——出于性能原因,使用严格的数据字段是一个好主意,但由于我喜欢记录,我最终会选择使用
{-# LANGUAGE TemplateHaskell -#}
{-# LANGUAGE DeriveFoldable -#}
{-# LANGUAGE DeriveFunctor -#}
{-# LANGUAGE DeriveTraversable -#}
{-# LANGUAGE RecordWildCards #-}
import Control.Lens
data Point a = Point { _pr1 :: !a
, _pr2 :: !a
} deriving (..)
$(makeLenses ''Point)
使用norm Point{..}=sqrt(_pr1^2+_pr2^2)
和RecordWildCards
以及镜头的所有细节,您可以从中受益
更新(2017-09-03):
就在最近,我发现了,它提供了严格的数据类型以及严格的IO操作。有一件事让我印象深刻,那就是
请注意,strict可能不是monad,因为返回⊥ >>= f=⊥
不一定与f相同⊥代码>
我认为这也适用于严格对-因此,在定义和/或使用严格数据类型时请记住这一点。您可以使用控制中的第一个和第二个。Arrow
或\u 1
和\u 2
来修改/提取元组值。是否有一些规范的地方存在争议“关于记录是否被列出?”贾蒙德说得相当全面。一般来说,ghc wiki是查找关于“现代”Haskell的信息和讨论的好地方。类型点a=(a,a)
只是一个别名,或者新类型点a=点(a,a)
“仅在操作上是正确的:在类型级别上,只有后者才允许编译器帮助您区分点和元组,并允许您为点
添加新实例。