Reputation: 17
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.
Upvotes: 0
Views: 152
Reputation: 21811
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:
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
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
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!"
Upvotes: 2