Reputation: 59
I have a function, dir_con :: (Int -> Dir)
I want to pattern match to find which specific constructor dir_con is. The data type is:
data Dir = Define Int
| Equals Int
| Data Int
| LCset Int
| NoArg Int
So, dir_con will either be Define, Equals etc. It is passed to a function and I want to pattern match like so:
case dir_con of
NoArg -> Do something specific
_ -> Do something for the rest
The compiler doesn't like that. Error message is Couldn't match expected type 'Int -> Dir' with actual type 'Dir'
.
Surely NoArg
is a constructor of type (Int -> Dir)
? Does Haskell not allow this type of pattern match? I have to do this because the Dir
constructors come from a map. Is there a suggestion on how I can treat NoArg
differently?
Upvotes: 2
Views: 298
Reputation: 60523
If all your constructors are of type Int -> Dir
, then I would suggest the same as @hammar: make the constructor type an enumeration:
data DirType = Define | Equals | Data | LCset | NoArg
data Dir = Dir DirType Int
Then you can probably refactor whatever needs to know what constructor it is to use a value of DirType
there instead.
The essential problem with trying to determine what constructor dir_con :: Int -> Dir
is is that not everything of that type is a constructor. For exampe:
dispatch :: Int -> Dir
dispatch 0 = Define 0
dispatch 1 = Equals 1
dispatch n = NoArg n
There is no good answer that you can get for "which constructor" dispatch
is.
If Dir
were parametric
data Dir a = Define a | Equals a | Data a | LCset a | NoArg a
then there is a type of Dir
constructors; namely forall a. a -> Dir a
(you need the {-# LANGUAGE RankNTypes #-}
extension to work with such types). Such a type disallows shenanigans like dispatch
which inspects its argument. So if you have:
dir_con :: forall a. a -> Dir a
then you can inspect its constructor by passing it a trivial value
case dir_con () of
...
Even though you only ever practically use a Dir Int
, the polymorphism allows you to be more descriptive with your types.
Upvotes: 1
Reputation: 19657
You cannot pattern match on functions. A value of type Dir
is built by applying one of several constructors, but dir_con
is a function of type Int -> Dir
.
You probably want to apply the function before pattern matching:
case dir_con 7 of -- `7` is just an arbitrary value I'm passing
NoArg _ -> ...
_ -> ...
In addition, you have to match on the argument of the NoArg
constructor as well, or else you'll get another type error after adding the argument to dir_con
.
In your concrete situation, you'll most likely not want to pass a literal integer, but perhaps an argument you're getting from elsewhere:
myfun n = ... case dir_con n of
NoArg _ -> ...
_ -> ...
Upvotes: 4
Reputation: 137997
Two ways:
case dir_con of
NoArg _ -> Do something specific
_ -> Do something for the rest
You're matching the /value/ not the constructor function.
Or, usingr record syntax:
case dir_con of
NoArg {} -> Do something specific
_ -> Do something for the rest
which is good hygiene, as it is neutral with respect to the number of fields.
Upvotes: 5