0

I am actually new to haskell. Trying to run this code:

Return the tag name of a XML element

getName :: Content -> Name
getName (CElem (Elem nme atts cs)) = nme 

I've got the following error:

Expecting one more argument to `Content'
    In the type signature for `getName': getName :: Content -> Name

could you please help me to fix it.

bheklilr
  • 53,530
  • 6
  • 107
  • 163
  • What library are you using? Can you provide more information on your specific problem? – bheklilr May 16 '14 at 12:59
  • I am using HaXML 1.13.3 and Haskell compiler GHC7.6.3. – user3644664 May 16 '14 at 13:04
  • *Hint:* [`Content`](http://hackage.haskell.org/package/HaXml-1.23.3/docs/Text-XML-HaXml-Types.html#t:Content) is not a type, but a type *constructor*. So as error message suggests, you need to pass one argument to `Content`, e.g. `Content i`. – fizruk May 16 '14 at 13:30
  • What happens if you remove the type signature? Does it compile? If so, can you examine the type in GHCi? – bheklilr May 16 '14 at 13:33

1 Answers1

2

There are several problem with the code you posted, all of which can be seen by looking at the types alone. Here is the relevant type information from the docs:

data Content i = CElem (Element i) i
               | CString Bool CharData i
               | CRef Reference i
               | CMisc Misc i
               deriving Show

data Element i = Elem QName [Attribute] [Content i] deriving (Eq, Show)

data QName = N  Name
           | QN Namespace Name 
           deriving (Eq,Show)

data Reference = RefEntity EntityRef
               | RefChar CharRef
               deriving (Eq,Show)
type EntityRef    = Name

Here are your problems with the posted code:

  1. The type Content has kind * -> *, that is, Content is a type constructor which takes a type parameter as an argument and returns a type. You can't pass a partially applied type (Content) as a value to a function, which means your getName function should have the signature

    getName :: Content i -> Name
    
  2. Your pattern match on CElem only has one argument, but you can see from its definition above that it takes two. Since you are only using one of the constructor values, we can replace the others with _. So far, we have this:

    getName :: Content i -> Name
    getName (CElem (Elem nme _ _) _) = nme
    
  3. The first argument of the Elem constructor has type QName, but your signature suggests you want to return something of type Name. This means we can't just return nme. Instead, we need to pattern match again on the N constructor to pull out the name:

    getName :: Content i -> Name
    getName (CElem (Elem (N nme) _ _) _) = nme
    

While the final definition should compile, you'll likely get runtime errors due to a refutable pattern match. This means you will try to match a value against a pattern, but the pattern is not found. For example, the first argument of Elem has type QName, but could instead be constructed using the QN constructor. Thus it would be better if we add a case for that constructor:

getName (CElem (Elem (QN _ nme) _ _) _) = nme

Similarly, you should consider all of the other possibilities for a refutable pattern match: the Elem constructor is fine; its type Element i only has one constructor. The type Content i has multiple constructors. The CString constructor doesn't have an obviously-derivable value of type Name, so we'll ignore it for now. CRef does, so we'll add a case for it:

 getName (CRef (RefEntity nme) _) = nme

The other constructor for Reference doesn't have a name, so we ignore it. I'll leave CMisc up to you.

 This means that the final definition of `getName` should looks something like this:

 getName :: Content i -> Name
 getName (CElem (Elem (N nme) _ _) _) = nme
 getName (CElem (Elem (QN _ nme) _ _) _) = nme
 getName (CRef (RefEntity nme) _) = nme
 -- maybe add a case for CMisc here
 getName _ = error "Content constructor doesn't have a Name!"
crockeea
  • 21,651
  • 10
  • 48
  • 101
  • Now that I've solved your problem, let me address some other issues. First, these are all very basic Haskell techniques, which indicates you need to read a tutorial before going any further (or asking more questions on SO). You can find a plethora [here](http://stackoverflow.com/questions/1012573/getting-started-with-haskell). – crockeea May 16 '14 at 13:47
  • Simplicity aside, you question has other glaring issues which nearly got it closed. It is very difficult to diagnose compile errors without a *compiling*, *minimal example*. For example, you didn't even mention you used `HaXML` in the original question, and I still had to search through it to find the relevant type information. If you had included the import statement (i.e. made your code compile) it would be more likely to get answers in the future. You can find more information about asking good questions [here](http://stackoverflow.com/questions/how-to-ask). – crockeea May 16 '14 at 13:48
  • If this answer was helpful to you, you can accept it by clicking the check mark next to it. – crockeea May 17 '14 at 18:39