首页 > 解决方案 > 不在范围内:数据构造函数“Song” - Haskell

问题描述

type Song = (String, String, Int) --(title, artist, sales)

database :: [Song]
database = [("Amon Amarth","Ravens flight", 1), 
  ("Amon Amarth","Shield wall", 11),
  ("Amon Amarth","The way of vikings", 105),
  ("Elijah Nang","Journey to the west", 1000),
  ("Elijah Nang","Tea house", 7),
  ("Pink Floyd","Wish you were here", 123),
  ("Amon Amarth","Raise your horns", 9001),
  ("NLE Choppa","Walk 'em down'", 69420),
  ("Elijah Nang","Kumite", 1337),
  ("NLE Choppa","Shotta flow 6", 511),
  ("Pink Floyd","Comfortably numb", 9),
  ("Pink Floyd","Shotta flow 6", 711), -- changed to match the name of an nle choppa song as requested
  ("Johannes Chrysostomus Wolfgangus Theophilus Mozart","Requiem", 10203948),
  ("Elijah Nang","Kenjutsu water style", 1),
  ("NLE Choppa","Shotta flow 5", 1),
  ("Pink Floyd","High hopes", 1),
  ("Amon Amarth","Deceiver of the gods", 1),
  ("Johannes Chrysostomus Wolfgangus Theophilus Mozart","Turkish march", 1),
  ("Chance The Rapper","Cocoa butter kisses", 1),
  ("Chance The Rapper","Favourite song", 1),
  ("Chance The Rapper","Hot shower", 1),
  ("Chance The Rapper","High hopes", 1)] 


getTrackSale :: Int -> String -> String -> String --(index, artist, track, sales)
getTrackSale index artist track
  | ((getArtist(database!!index) == artist) && (getTrack(database!!index) == track)) = getTrackSale(database!!index)
  | otherwise = getTrackSale(index + 1 artist track)


task2 = getTrackSale(0 "Chance The Rapper" "Hot Shower")

getArtist :: Song -> String
getArtist (Song y _ _) = y

getTrack :: Song -> String
getTrack (Song _ z _) = z

getSale :: Song -> Int
getSale (Song _ _ x) = x

我无法弄清楚这意味着什么或如何解决它,我之前已经编写了与三个“get”函数相同的函数并且它们没有问题,但我之前确实使用了“type”声明,所以我想就是这样。我有使用相同类型声明的示例代码,它工作正常,所以我在这里有点迷失。

标签: databasehaskelltypesconstructorscope

解决方案


你写

type Song = (String, String, Int)

这意味着 thatSong是 的类型同义词(String, String, Int)也就是说, aSong实际上只是一个有序三元组,使用有序三元组构造函数构造(,,)。但后来你写

getArtist :: Song -> String
getArtist (Song y _ _) = y

getTrack :: Song -> String
getTrack (Song _ z _) = z

getSale :: Song -> Int
getSale (Song _ _ x) = x

(不存在的)Song数据构造函数上的模式匹配。

您可以通过编写来坚持类型同义词

getArtist :: Song -> String
getArtist (y, _, _) = y

等等。或者您可以创建Song自己的数据类型:

data Song = Song
  { getArtist :: String
  , getTrack :: String
  , getSale :: Int }

在这种情况下,您必须修改database定义以使用Song构造函数。使用自定义数据类型声明更符合习惯和更自文档化,它使 Haskell 的类型系统做更多的工作来帮助您发现代码中的错误。作为一般规则,我建议 Haskell 初学者完全避免使用类型同义词,而更有经验的 Haskell 程序员仅在某些特殊情况下很少使用它们。特别是,类型同义词与扩展结合起来非常有用,与and扩展TypeFamilies结合起来有些用处,但根据我的经验,其他方面往往更令人困惑而不是有用。ConstraintKindsRankNTypes


推荐阅读