1

我正在尝试修改数据库列表中的一个元素以添加到评分中,我想返回一个修改后的数据库,其中包含新元素。我知道 Haskell 有不可变的东西,但同时我不能完全掌握如何去做。

以下是类型:

data Film = Film Director Title Year Ratings
     deriving (Show,Ord,Eq, Read)

testDatabase :: [Film]

我唯一的代码是:

--addRating :: Rating -> Film -> Film
--addRating rating (Film name director year ratings)= (Film name director year [(ratings : rating)])


--findFilm name = head $ filter (\(Film n _ _ _) -> n == name) testDatabase 

查找电影效果很好,但我无法让 addRating 工作,即使它确实工作我仍然不明白如何将它们全部组合在一起以调用函数以返回具有元素的电影列表新的评级就可以了。

4

4 回答 4

3

你几乎说对了:

addRating rating (Film name director year ratings)
    = (Film name director year [(ratings : rating)])

目前你有代码:

[(ratings : rating)]

:运算符具有 type a -> [a] -> [a],它需要一个元素并将其附加到列表的开头而不是列表的末尾,因此您需要切换参数。

此外,语法[x],当像您一样使用时,会创建一个由一个元素组成的列表。如果您在此处使用它,它将获取您创建的列表并将其包装在另一个列表中,这不是您想要的。

您只需要制作一个列表,其中包含rating前面的其余部分ratings

(rating : ratings)
于 2012-05-02T01:52:47.127 回答
2

正如 Porges 所说,你得到ratingratings错误的顺序。您可能会发现记录语法方法更符合您的喜好:

data Film = Film {director :: Director, title :: Title, year :: Year, ratings :: Ratings}
                deriving (Show,Ord,Eq, Read)

addRating :: Rating -> Film -> Film
addRating rating film = film {ratings = rating : ratings film}

在这里,film {director = "Martin Scorsese"}'updates'director字段,即表达式引用了Film一个不同的导演,但其他一切都相同。但是,在当前情况下,您需要旧ratings字段的内容,因此您需要ratingratings film. 这种声明类型的方式使派生Show具有不同的外观。

于 2012-05-02T02:46:34.050 回答
0

...我无法让 addRating 工作,即使它确实工作我仍然不明白如何将它们全部组合在一起以调用一个函数来返回一个包含新评级元素的电影列表在上面。

似乎您想要一个返回新数据的函数,以一种可以“在旧数据所在的位置”访问的方式。

这里要理解的关键是仅此一项就会使其成为可变数据。

函数式编程提供的一件事是保证数据始终相同。在命令式(非函数式)语言中,如果您有多个可能会更改数据的进程,则必须小心它们不会以意想不到的方式修改彼此的数据。不可变的数据使这不是问题。

如果您真的想要破坏性更新,有办法做到这一点。但是,您可能正在寻找的是State monad,这是一种很好的方式来“携带”状态而无需破坏性更新。

于 2012-05-02T03:13:21.813 回答
0

对“不可变事物”的关键理解是,您不需要修改给定的事物,您只需创建一个稍微不同的“副本”并将其作为结果返回。例如,您有一个l包含[1,2,3]. 当你这样做时l ++ [4],你会回来[1,2,3,4]但价值l没有改变

对你的电影记录使用同样的原则——你已经很接近了。

正如其他人指出的那样,您在(ratings : rating)表达式中混淆了您的类型。要使用:,元素在前面,列表在后面。您可以切换您的类型,但这会将新评级放在前面,这可能是您不想要的。另一种方法是使用++,它附加两个列表。因此,要使用++,您需要从单个元素中创建一个列表,并将其附加到现有评级中。

addRating :: Rating -> Film -> Film
addRating rating (Film name director year ratings) =
    (Film name director year (ratings ++ [rating]))
于 2012-05-03T04:19:27.827 回答