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} 哪种设计/风格更好?为什么?在哈斯克尔,唱片是一个有争议的话题。社会上有一个共识,即由于许多原因,现有的实施并不理想,目前正在采取措施解决这一

我可以想出三种方法在Haskell中将几何点定义为代数数据类型。我想将其定义为代数数据类型,以便更好地编写文档

作为元组类型:

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)
“仅在操作上是正确的:在类型级别上,只有后者才允许编译器帮助您区分点和元组,并允许您为
添加新实例。