Mic*_*ron 2 oop polymorphism haskell functional-programming list
为什么Haskell允许在第一个例子中做一个Shape列表,但不像第二个例子那样?据我所知,两个列表都有元素
{ name :: String, position :: Vector3D, radius :: Double }
Run Code Online (Sandbox Code Playgroud)
要么
{ name :: String, position :: Vector3D, dimensions :: Vector3D }.
前1:
data Shape
= Sphere { name :: String, position :: Vector3D, radius :: Double }
| Prism { name :: String, position :: Vector3D, dimensions :: Vector3D }
Run Code Online (Sandbox Code Playgroud)
前2:
data Sphere = Sphere { name :: String, position :: Vector3D, radius :: Double }
data Prism = Prism { name :: String, position :: Vector3D, dimensions :: Vector3D }
Run Code Online (Sandbox Code Playgroud)
我想知道为什么可以做一个Shape列表,但没有Sphere和Prism的多态列表,即使它们具有与通过数据类型"Shape"声明的成员相同的成员.
And*_*ewC 10
在你的第二个例子中,
data Sphere = SphereTag { sphereName :: String,
spherePosition :: Vector3D,
sphereRadius :: Double }
data Prism = PrismTag { prismName :: String,
prismPosition :: Vector3D,
prismDimensions :: Vector3D }
Run Code Online (Sandbox Code Playgroud)
你已经声明这些是两种不同的数据类型.你可以有类型[Sphere]和[Prism]而不是[Shape](因为你没有定义Shape在这个例子中类型).
我已经改名为田,否则name有两个类型name :: Sphere -> String和name :: Prism -> String,这是不允许的,而无需使用类型类.
我已重命名SphereTag并PrismTag明确了类型Sphere和数据构造函数之间的区别SphereTag
在第一个例子中
data Shape
= SphereShape { name :: String, position :: Vector3D, radius :: Double }
| PrismShape { name :: String, position :: Vector3D, dimensions :: Vector3D }
Run Code Online (Sandbox Code Playgroud)
有一种类型,所以你可以制作[Shape].
结合两种类型的经典方法是使用Either,它使用Left或标记两种类型的数据Right:
type PrismOrSphere = Either Prism Sphere
myList = [Left (SphereTag "this" ...), Right (PrismTag "that" ....), ....]
Run Code Online (Sandbox Code Playgroud)
但你的自定义Shape类型可能会更好.
尽量不要将OOP教学示例重新用作函数式编程示例.OOP示例旨在首先教授OO原则,然后编程编程,它们的设计非常适合开发OO和命令式思维.
这就像试图通过在空车停车场学习驾驶飞机一样.在飞机上停车很慢,但这可能是你开车时学到的第一件事.
如果你坚持通过试图复制你的驾驶课程来学习飞行,你会发现你的飞机是一种非常不方便的汽车,不适合很多道路.
您应该使用一套精心编写的示例来教授函数式编程.我推荐Learn You a Haskell for Great Good,它包含web和dead tree版本.
在面向对象编程中,您通常称为多态的是使用超类实现的.你可以拥有一个由Shape子类型组成的ShapeList或一个由管理器和清理器组成的EmployeeList,但是在传统的OOP中,你需要编写不同但相似的代码来实现.sort每个方法的方法.我们可以称之为这种亚型多态性.它与从泛型中获得的多态性不同,在泛型中您可以编写单个方法来处理任何类型.
在函数式编程中,你通常称之为多态的是通过完全不知道你的数据类型来实现的,所以你可以编写一个函数reverse :: [a] -> [a],它可以用于任何可能的列表,Shapes或Spheres或Employees或者其他什么,更像是泛型但是没有运行时类型的数据开销(参见Haskell擦除类型吗?).我们可以称之为参数多态.它与从类型类中获得的多态性不同,在类型类中,允许多个类型具有相同的命名函数.
因为在EX1,Sphere而Prism不是类型,但构造函数.它们都属于同一类型Shape.因此,您可以创建一个列表[Shape].而且,因为它们不是类型,[Sphere]所以甚至没有意义,因为Sphere它不在类型命名空间中.我不知道这是否令你感到困惑,但是当我开始学习Haskell时,我混淆了构造函数和OO子类.它们是不同的.在那种情况下(ex1)你不能有这样的事情:
radius :: Sphere -> Double
Run Code Online (Sandbox Code Playgroud)
因为Sphere不是一种类型.Sphere是一个返回的函数Shape.
现在,在EX2,Sphere并且Prism是类型的,所以你要么有
[Sphere][Prim][Either Sphere Prism].另一种解决方案是为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
Run Code Online (Sandbox Code Playgroud)
现在,您可以拥有一个列表同质的形状,例如:
names :: Shape s => [s] -> [String]
names ss = map name ss
Run Code Online (Sandbox Code Playgroud)
同质,我的意思是你不能在同一个列表中混合棱镜和球体.