想象一下,我想编写一个处理播客feed的应用程序。为了存储来自这种提要的解析信息,我将编写如下内容:
data Podcast = Podcast {
podcastTitle :: String, -- ^ title of podcast
episodes :: [Episode] -- ^ list of episodes of podcast
... -- ^ some other fields
} deriving (Show)
data Episode = Episode {
episodeTitle :: String, -- ^ title of episode
podcast :: Podcast -- ^ podcast this episode belongs to
... -- ^ some other fields
} deriving (Show)
上面的数据记录定义反映了数据类型之间常见的1:n关系:播客有很多插曲,而该插曲属于一个播客。现在,我在定义此类播客时遇到了问题:定义
Podcast
我已经需要情节列表,但是要定义Episode
实体,我需要Podcast
实体。在我看来,解决这种循环依赖性在haskell中是不可能的...我还认为上面的代码是我用其他语言编写的程序的一部分。在上面的样式中,我将以python为例,但是这种编程语言具有状态概念。在python中,我可以先定义一个没有情节的
Podcast
实体,然后使用定义的Podcast
实体初始化所有情节,然后将播客的episodes
字段设置为情节列表。我的问题:在播客和剧集之间建立1:n关系的haskell方法是什么?
对评论中问题的回答:
为什么一集必须引用特定播客?有一个功能会很好
podcast :: Episode -> Podcast
每当我需要时,它都会返回该剧集的播客。我知道,一种解决方案是将
Podcast
实体也传递给每个剧集的功能,即我替换每个功能func1 :: Episode -> Something
我需要上面的
podcast
函数的地方func1 :: Podcast -> Episode -> Something
只需编写尽可能少的代码,而不必将
Podcast
实体随处携带都是很好的。也许我稍微改变了我的问题:定义
Episode
数据记录而没有podcast
字段是完全可以的。如何实施podcast :: Episode -> Podcast
在这种情况下?
如果以后有人进行播客(包括其他播客的剧集)怎么办?就我而言,这不会发生,即使是这种情况,也可以将同一集视为不同的集。 (实际上,考虑到此问题会将1:n关系提升为n:n关系,但是如何在haskell中定义这些关系的主要问题仍然相同)。
最佳答案
在Haskell中,循环依赖实际上非常容易。在let
语句中,任何绑定的定义都可以引用任何其他绑定。
let pc = Podcast "the name" [ep1, ep2]
ep1 = Episode "first" pc
ep2 = Episode "second" pc
懒惰会为您解决这个问题。
但是,作为一般规则,DBMS是此类信息的最佳选择。