Haskell - 类型类的实例列表

15

我是Haskell的新手,为了提高自己的编程水平,我想做一个简单的Web服务器。我希望能够灵活地表示页面,所以我的想法是让网页成为可渲染数据的列表(就像在Java中你可以创建实现某个接口的对象列表)其中Renderable定义为:

class Renderable a where
    render :: a -> IO String

不幸的是,我了解到列表必须是具体类型,因此我只能制作一种可渲染数据类型的列表。而且似乎无法创建受类型类约束的数据,因此我不能创建像RenderList这样的东西。我的临时解决方案是这样的:

myPage =
    [render $ someData
    ,render $ someMoreData
    ,render $ someOtherData
    ...
    ]

但这种做法感觉很别扭,使用类型类没有任何好处,并且感觉应该有更好的方法。所以我想知道是否有什么方式可以重新组织我的代码,使其更加清晰、符合标准的Haskell实践,并且仍然易于扩展?

谢谢。


为什么不使用现有的Web框架?Yesod、Snap、Happstack都是不错的选择。 - Kristopher Micinski
1
@KristopherMicinski 我不想这样做,因为我正在利用它来学习 Haskell。 - Terrance Niechciol
说实话:在Haskell中进行低级Web编程是很困难的!正确处理IO仍然没有完全理解,并且以函数式风格进行编程是一门艺术。这听起来更像是对Haskell感到恼火而不是学习它的更好方式。我仍然认为,如果您使用预先制作的Web框架,您可以学习所有核心功能,并启动“真实”项目,同时避免更少的挫败感。 - Kristopher Micinski
你可以轻松地通过在列表上使用“map”来清理它。但是,你要对什么进行映射呢?你不能创建一个包含不同类型数据的列表,这就是我试图解决的问题。 - Terrance Niechciol
是的,但是使用答案中概述的存在类型方法,您可以... - Kristopher Micinski
显示剩余2条评论
2个回答

13

你正在尝试实现面向对象的设计风格。例如,在Java中,你可以拥有一个 List<Renderable> 就可以了。但是在Haskell中,这种设计风格略微不太自然;你需要创建一个包装类型来限制存在类型,如所示的Haskell维基页面上的存在类型 。例如:

class Renderable_ a where
  render :: a -> IO String

data Renderable = forall a. Renderable_ a => Renderable a
instance Renderable_ Renderable where
  render (Renderable a) = render a

你可以拥有一个Renderable列表,并以任何你喜欢的方式进行渲染。但是,这种面向对象的风格在Haskell中并不自然。通过重新思考数据结构,可能可以避免这种情况。你说你“想让页面表示方式可扩展”,考虑其他方法来实现。

无关紧要的提示:我猜测render不需要生成IO String操作。如果可能的话,请尽量避免在设计核心中使用IO


5

请查看这个页面关于Haskell的异构集合.

它提供了多种方法的想法。


谢谢回复。不幸的是,似乎最接近我想做的事情的那个——4. 存在类型——仍然有与我的解决方案相同的问题。我不明白他们用什么方法创建 hlist 要比使用 String 和 show 而不是 Showable 和 pack 好到哪里去了。 - Terrance Niechciol

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接