Haskell中的异构多态性(正确方式) [英] Heterogeneous polymorphism in Haskell (correct way)
问题描述
让一个模块抽象 Area
操作(坏定义)
class Area someShapeType where
area :: someShapeType - > Float
- 模块实用程序
sumAreas :: Area someShapeType => [someShapeType]
sumAreas = sum。地图区域
让一个后验显式形状类型模块)
data Point = Point Float Float
data Circle = Circle Point Float
instance表面圆形其中
表面(Circle _ r)= 2 * pi * r
数据Rectangle =矩形点点
实例表面矩形其中
surface x1 y1)(点x2 y2))= abs $(x2-x1)*(y2-y1)
让一些数据
c1 = Circle(Point 0 0)1
r1 = Rectangle (点11)
然后,尝试使用
totalArea = sumAreas [c1,r1]
[c1,r1]
类型必须扩展为 [Circle]
或
! (无效)
我可以使用 forall
和 code> data 类型如下
data Shape = forall a。表面a =形状a
sumSurfaces :: [Shape] - > Float
sumSurfaces = sum。 map(\(Shape x) - > surface x)
/ p>
sumSurfaces [Shape c1,Shape r1]
但我认为,使用数据Shape
和 Shape
构造函数 [Shape c1,...]
和lambda参数)是丑陋的(我的第一个[和坏的]方式是漂亮的)。
Haskell中的异构多态性是什么?
非常感谢您的时间! p>
您的存在解决方案是好的。使用 GADT
可能是更漂亮,如:
{ - #LANGUAGE GADTs# - }
数据形状其中
Shape ::(Surface a)=> a - >形状
...并且像leftaraoundabout建议,你可以不同结构你的代码。 p>
但我认为你基本上违反了表达式问题这里;或者更准确地说:通过试图巧妙地构造您的代码(每个具有类的形状的独立类型),预期EP会为您自己带来新的困难。
查看由Wouter Swierstra提供的有趣的数据类型单项,以获得我希望与之相关的优雅解决方案你的问题。也许有人可以评论与好的包裹在黑客看看那是受那篇文章的启发。
Let a module to abstract Area
operations (bad definition)
class Area someShapeType where
area :: someShapeType -> Float
-- module utilities
sumAreas :: Area someShapeType => [someShapeType]
sumAreas = sum . map area
Let a posteriori explicit shape type modules (good or acceptable definition)
data Point = Point Float Float
data Circle = Circle Point Float
instance Surface Circle where
surface (Circle _ r) = 2 * pi * r
data Rectangle = Rectangle Point Point
instance Surface Rectangle where
surface (Rectangle (Point x1 y1) (Point x2 y2)) = abs $ (x2 - x1) * (y2 - y1)
Let some data
c1 = Circle (Point 0 0) 1
r1 = Rectangle (Point 0 0) (Point 1 1)
Then, trying to use
totalArea = sumAreas [c1, r1]
the [c1, r1]
type must be expanded to [Circle]
or [Rectangle]
! (and is not valid)
I can do using forall
and a extra data
type like this
data Shape = forall a . Surface a => Shape a
sumSurfaces :: [Shape] -> Float
sumSurfaces = sum . map (\(Shape x) -> surface x)
then, next code run successfully
sumSurfaces [Shape c1, Shape r1]
but I think, the use of data Shape
and Shape
constructor (on [Shape c1, ...]
and lambda argument) is ugly (my first [and bad] way is pretty).
What is the correct way to do "Heterogeneous polymorphism in Haskell"?
Thank you very much for your time!
Your existential solution is okay. It might be "prettier" to instead use a GADT
, as in:
{-# LANGUAGE GADTs #-}
data Shape where
Shape :: (Surface a) => a -> Shape
...and as leftaraoundabout suggests, you may be able to structure your code differently.
But I think you've basically hit up against the Expression Problem here; or perhaps, more accurately: by trying to structure your code cleverly (separate type for each shape with classes) in anticipation of the EP you've introduced new difficulties for yourself.
Check out the fun Data Types a la Carte by Wouter Swierstra for an elegant solution to what I hope is related to your problem. Maybe someone can comment with good packages on hackage to look at that are inspired by that paper.
这篇关于Haskell中的异构多态性(正确方式)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!