Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
List 为什么Haskell允许列出形状,但不允许列出正方形、圆形或三角形_List_Oop_Haskell_Functional Programming_Polymorphism - Fatal编程技术网

List 为什么Haskell允许列出形状,但不允许列出正方形、圆形或三角形

List 为什么Haskell允许列出形状,但不允许列出正方形、圆形或三角形,list,oop,haskell,functional-programming,polymorphism,List,Oop,Haskell,Functional Programming,Polymorphism,为什么Haskell允许像第一个例子那样列出形状,而不像第二个例子那样?据我所知,两个列表中的元素都是 { name :: String, position :: Vector3D, radius :: Double } 或 {name::String,position::Vector3D,dimensions::Vector3D} 例1: 例2: 我想知道为什么可以创建一个形状列表,但不能创建Sphere和Prism的多态列表,即使它们的成员与通过数据类型“Shape”声明的成员相同。您所说

为什么Haskell允许像第一个例子那样列出形状,而不像第二个例子那样?据我所知,两个列表中的元素都是

{ name :: String, position :: Vector3D, radius :: Double }

{name::String,position::Vector3D,dimensions::Vector3D}

例1:

例2:


我想知道为什么可以创建一个形状列表,但不能创建Sphere和Prism的多态列表,即使它们的成员与通过数据类型“Shape”声明的成员相同。

您所说的实际上并不正确,您提供的两个示例都不是列表

上面的示例是Algebric数据类型的示例

您显示的第二个示例是Sphere的记录数据声明示例:

data Sphere = Sphere { name :: String, position :: Vector3D, radius :: Double }
data Prism =  Prism { name :: String, position :: Vector3D, dimensions :: Vector3D }
也就是说,在Haskell列表中是同质类型。它们只能保存相同类型的值。(尽管您可以通过使用存在量化来克服这一问题,但不要将其作为反模式使用。)

同样从您的示例一中,您可以将其作为类型
[Shape]
的列表,该列表可以包含
球体
棱镜
。例如:

λ> let a = Sphere "sph1" 2.2 3.4
λ> let b = Prism "prism" 3.4 4.8
λ> let c = [a,b]
λ> :t c
c :: [Shape]
在上面的例子中,我假设
Vector3D
属于
Double

不同的类型 在你的第二个例子中

data Sphere = SphereTag { sphereName :: String, 
                          spherePosition :: Vector3D, 
                          sphereRadius :: Double }
data Prism = PrismTag { prismName :: String, 
                        prismPosition :: Vector3D, 
                        prismDimensions :: Vector3D }
您已经声明这是两种不同的数据类型。您可以使用类型
[Sphere]
[Prism]
,但不能使用
[Shape]
(因为在本例中您尚未定义
形状
类型)

我之所以重命名这些字段,是因为除此之外
name
有两种类型
name::Sphere->String
name::Prism->String
,如果不使用typeclass,这是不允许的

我已经重命名了
SphereTag
PrismTag
,以明确类型
Sphere
和数据构造函数
SphereTag

一种 在第一个例子中

data Shape
   = SphereShape { name :: String, position :: Vector3D, radius :: Double }
   | PrismShape { name :: String, position :: Vector3D, dimensions :: Vector3D }
有一种类型,因此您可以制作
[Shape]

任意标记的并集 组合两种类型的经典方法是使用其中一种,即使用
Left
Right
标记两种类型的数据:

type PrismOrSphere = Either Prism Sphere

myList = [Left (SphereTag "this" ...), Right (PrismTag "that" ....), ....]
但是你最好还是使用你的自定义形状类型

来自OOP的建议 尽量不要将OOP教学示例作为函数编程示例重复使用。OOP示例的目的是先教您OO原则,然后再教您编程,它们的设计非常适合于开发您的OO和命令式思维

这就像是在一个空旷的停车场附近驾驶飞机一样。在飞机上绕着停车场慢慢走是很困难的,而这可能是你开车时学到的第一件事

如果你坚持通过模仿驾驶课程来学习飞行,你只会认为你的飞机是一种非常不方便的汽车,不能在很多道路上行驶

您应该使用一组编写良好的示例来教授函数式编程。我推荐web版本和死树版本

面向对象与FP中的多态性 在面向对象编程中,通常所称的多态性是使用超类实现的。您可以使用由Shape子类型组成的ShapeList,也可以使用由经理和清洁工组成的EmployeeList,但在传统的OOP中,您需要编写不同但相似的代码来对每种类型实现
。sort
方法。我们可以称这种亚型为多态性。它不同于从泛型中获得的多态性,在泛型中,您可以编写一个方法来处理任何类型


在函数式编程中,通常所称的多态性是通过完全不知道数据类型来实现的,因此您可以编写一个函数
反向::[a]->[a]
,该函数适用于任何可能的列表、形状、球体或雇员等,更像泛型,但没有运行时类型的数据开销(请参阅)。我们可以称之为参数多态性。这与类型类中的多态性不同,在类型类中,您允许多个类型具有相同的命名函数。

我想您可能会对Haskell中类型的工作方式感到困惑。Haskell使用参数多态性和基于类的即席多态性。它没有任何类似于结构子类型的东西。为数据构造函数的字段指定的名称与其中声明的类型绑定;它们不能在其他地方重复使用。即使有允许这种重用的GHC扩展,重用的名称也彼此不相关。

因为在ex1中,
Sphere
Prism
不是类型,而是构造函数。它们都是相同类型的
形状
。因此,您可以创建
[Shape]
的列表。此外,由于它们不是类型,
[Sphere]
甚至没有意义,因为
Sphere
不在类型命名空间中。我不知道这是否让你感到困惑,但当我开始学习Haskell时,我把构造函数和OO子类混为一谈。他们是不同的。在这种情况下(ex1),您不能有以下情况:

radius :: Sphere -> Double
因为
Sphere
不是一种类型
Sphere
是一个返回
Shape
的函数

现在,在ex2中,
Sphere
Prism
是类型,因此您可以选择其中一种

  • 球体列表
    [Sphere]
  • 棱镜列表
    [Prim]
  • AndrewC
    [任一球面棱镜]
    指出的一个或多个顺序的列表
另一种解决方案是为有名称和位置的东西声明一个
Shape

class Shape  a where
    name :: a -> String
    position :: a -> Vector3D


data Sphere = Sphere { sphereName :: String, spherePosition :: Vector3D, ... }
instance Shape Sphere where
  name s = sphereName s
  position s = spherePosition

data Prism = Prism { primsName :: String, prismPosition :: Vector3D, ... ?
instance Shape Prirm where
     name p = prismName p
     position p = prismPosition p
现在,您可以有一个同质形状列表,例如:

names :: Shape s => [s] -> [String]
names ss = map name ss

“同质”是指不能在同一个列表中混合使用棱柱体和球体。

如果我理解正确,听起来您的理解是数据类型

data Shape
    = Sphere { name :: String, position :: Vector3D, radius :: Double }
    | Prism { name :: String, position :: Vector3D, dimensions :: Vector3D }
和t
class Shape  a where
    name :: a -> String
    position :: a -> Vector3D


data Sphere = Sphere { sphereName :: String, spherePosition :: Vector3D, ... }
instance Shape Sphere where
  name s = sphereName s
  position s = spherePosition

data Prism = Prism { primsName :: String, prismPosition :: Vector3D, ... ?
instance Shape Prirm where
     name p = prismName p
     position p = prismPosition p
names :: Shape s => [s] -> [String]
names ss = map name ss
data Shape
    = Sphere { name :: String, position :: Vector3D, radius :: Double }
    | Prism { name :: String, position :: Vector3D, dimensions :: Vector3D }
data Sphere = Sphere { name :: String, position :: Vector3D, radius :: Double }
data Prism = Prism { name :: String, position :: Vector3D, dimensions :: Vector3D }