import Data.Char
-- Sample test data
testData :: [Movies]
testData = [("Me and My Broken Heart","Rixton"),
("It’s My Birthday","will.i.am"),
("Problem","Ariana Grande")]
-- record a sale of a track
record :: [Movies] -> String -> String
record t a = []
record ((t, a): xs) a a
| t == a && a == a = [(t,a)]
| otherwise = record xs a t
正确的输出应该是数据库的修改版本。
答案 0 :(得分:6)
首先,因为你似乎正在学习,所以关于风格的一些注释:在这种情况下,以单数形式命名一个销售是一种惯例,并且列表他们用复数形式,即:
type Sale = (String, String, Int)
type Sales = [Sale]
更好的是,通常会(根据预期的用途和品味)将Sale
转换为新类型或完整的ADT,因为这样可以提供更多抽象和类型安全。
其次,对于您的实际问题:您所看到的行为来自模式匹配的顺序。在你的第一场比赛中,
recordSale testData aTitle anArtist = []
在第二个模式可以应用之前, testDate
匹配任何列表,也是非空的列表。将其更改为
recordSale [] _ _ = []
你不会再获得空名单了。另外,正如@Aleksandar指出的那样,在列表不为空但过滤条件不匹配的情况下,您不应忘记保留列表的init。
答案 1 :(得分:4)
Haskell是一种函数式语言,它在类型系统中很好地封装了对数据的有状态修改。通常的方式"变异" Haskell中的值将是使用有状态计算(在ST
或State
Monad
中)或仅使用递归并复制值。我想你应该先学习后者。
如果[]
和aTitle
与列表中的任何条目都不匹配,您使用的功能将返回anArtist
。否则将返回一个包含一个单个元素的列表,即新修改过的列表。
您需要在遍历时逐步建立列表。记住,你基本上是在复制它:
-- record a sale of a track
recordSale :: [Sales] -> String -> String -> [Sales]
recordSale [] aTitle anArtist = []
recordSale ((title, artist, qty): xs) aTitle anArtist
| title == aTitle && artist == anArtist =
(title, artist, qty+1):recordSale xs aTitle anArtist
| otherwise = (title,artist,qty):recordSale xs aTitle anArtist
这应该会给你正确的结果。请注意这里有什么不同:你在两个案例中对函数进行了递归调用,在这两种情况下,你也要将修改或未修改的当前元素附加到列出你的建设。
您还应该考虑您的数据结构。具有注释的元组不是构建复杂数据结构的非常好的方法。尝试
data Record = Record { title :: String, artist :: String, quantity :: Integer }
你甚至可以像newtype
那样制作几个newtype Title = Title String
。请记住,在Haskell中创建数据类型很便宜,而且你应该不断地这样做。