Haskell中的异构多态性(正确方式) [英] Heterogeneous polymorphism in Haskell (correct way)

查看:375
本文介绍了Haskell中的异构多态性(正确方式)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

让一个模块抽象 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆