Not in scope: data constructor `Song' - Haskell

Viewed 54
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

I cannot figure out what this means or how to solve it, I've written identical functions to the three "get" functions before and they had no trouble, but i did use the "type" declaration before, so i imagine It's that. i have sample code using a identical type declaration in that works fine so im just a little lost here.

1 Answers

You write

type Song = (String, String, Int)

which means that Song is a type synonym for (String, String, Int). That is, a Song is actually just an ordered triple, constructed using the ordered-triple constructor (,,). But later you write

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

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

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

pattern matching on a (nonexistent) Song data constructor.

You can stick with the type synonym by writing

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

and so on. Or you can make Song its own datatype:

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

in which case you'll have to modify your database definition to use the Song constructor. Using a custom datatype declaration is more idiomatic and more self-documenting, and it makes Haskell's type system do more of the work of helping you find mistakes in your code. As a general rule, I recommend that Haskell beginners avoid type synonyms altogether, and that more experienced Haskell programmers use them only very rarely in certain special circumstances. In particular, type synonyms are very useful in combination with the TypeFamilies extension, and somewhat useful in combination with the ConstraintKinds and RankNTypes extensions, but otherwise tend to be more confusing than helpful, in my experience.

Related