Pattern matching 'undefined'
Hi, I want to represent a list of (key, values) in Haskell, where key are predefined strings So I define a datatype using field labels : data UR = MkUR { fieldA :: Int, fieldB :: Int, fieldC :: String } deriving (Show) and, for example, we have testUR = MkUR {fieldA = 1} testUR' = MkUR {fieldA = 2, fieldB = 3, fieldC = "C"} Now I want to write a function which transforms my datatype in [(String, String)] where a (key, value) element exists if the field is present, and none if the field does not exist. attrList :: UR -> [(String, String)] attrList u = al "fieldA" (fieldA u) ++ al "fieldB" (fieldB u) ++ al "fieldC" (fieldC u) al :: (Show a) => String -> a -> [(String, String)] al fn fv = [(fn, show fv)] Of course, as written, "attrList testUR'" succeeds and "attrList testUR" fails (Missing field in record construction Main.fieldB) I need to match against undefined, which is impossible. Is there a solution (probably involving irrefutable patterns, ~) ? Or is there a better way than using field labels (they are useful though, because I can define types to check the content at compile time, like data Location = Top | Bottom, which is far better than defining everything to be a String) Thank you for your help, Alain
On Sun, 25 May 2003 23:28:02 +0200 Alain Cremieux <alcremi@pobox.com> wrote:
Hi,
I want to represent a list of (key, values) in Haskell, where key are predefined strings
So I define a datatype using field labels :
data UR = MkUR { fieldA :: Int, fieldB :: Int, fieldC :: String } deriving (Show)
and, for example, we have
testUR = MkUR {fieldA = 1} testUR' = MkUR {fieldA = 2, fieldB = 3, fieldC = "C"}
Now I want to write a function which transforms my datatype in [(String, String)] where a (key, value) element exists if the field is present, and none if the field does not exist.
attrList :: UR -> [(String, String)] attrList u = al "fieldA" (fieldA u) ++ al "fieldB" (fieldB u) ++ al "fieldC" (fieldC u)
al :: (Show a) => String -> a -> [(String, String)] al fn fv = [(fn, show fv)]
(Wouldn't it make more sense to do attrList u = [al "fieldA" (fieldA u), al ...] with al :: ... -> (String,String)?)
Of course, as written, "attrList testUR'" succeeds and "attrList testUR" fails (Missing field in record construction Main.fieldB) I need to match against undefined, which is impossible.
So reify undefined.
Is there a solution (probably involving irrefutable patterns, ~) ?
You want values that may or may not be there. The standard solution is the Maybe type. Assuming you don't want to print out, "Just \"C\"", you can either make your own type with your own instance of show, or use a showValue function in al. The latter is likely preferable as there are quite a few utility functions for the Maybe type already and it's more familiar. You can define al with type ... -> Maybe (String,String) and attrList would just be catMaybes over a list of them, assuming you want attrList(MkUR (Just 5) Nothing (Just "Hello")) to give you [("fieldA","5"),("fieldC","\"Hello\"")] otherwise al can be ... -> (String, Maybe String) and you'd change show fv to fmap show fv, or just ... -> (String,String) with ("fieldB","undefined"/"Nothing"/""/whatever)
Derek Elkins wrote:
On Sun, 25 May 2003 23:28:02 +0200 Alain Cremieux <alcremi@pobox.com> wrote:
data UR = MkUR { fieldA :: Int, fieldB :: Int, fieldC :: String } deriving (Show)
and, for example, we have
testUR = MkUR {fieldA = 1} testUR' = MkUR {fieldA = 2, fieldB = 3, fieldC = "C"}
Now I want to write a function which transforms my datatype in [(String, String)] where a (key, value) element exists if the field is present, and none if the field does not exist.
attrList :: UR -> [(String, String)] attrList u = al "fieldA" (fieldA u) ++ al "fieldB" (fieldB u) ++ al "fieldC" (fieldC u)
al :: (Show a) => String -> a -> [(String, String)] al fn fv = [(fn, show fv)]
(Wouldn't it make more sense to do attrList u = [al "fieldA" (fieldA u), al ...] with al :: ... -> (String,String)?)
The idea is that the list may be empty, thus the choice of a list of pairs instead of a simple pair
Of course, as written, "attrList testUR'" succeeds and "attrList testUR" fails (Missing field in record construction Main.fieldB) I need to match against undefined, which is impossible.
So reify undefined.
How can I do that ? Can you give me an example ?
Is there a solution (probably involving irrefutable patterns, ~) ?
You want values that may or may not be there. The standard solution is the Maybe type. Assuming you don't want to print out, "Just \"C\"", you can either make your own type with your own instance of show, or use a showValue function in al. The latter is likely preferable as there are quite a few utility functions for the Maybe type already and it's more familiar. You can define al with type ... -> Maybe (String,String) and attrList would just be catMaybes over a list of them, assuming you want attrList(MkUR (Just 5) Nothing (Just "Hello")) to give you [("fieldA","5"),("fieldC","\"Hello\"")] otherwise al can be ... -> (String, Maybe String) and you'd change show fv to fmap show fv, or just ... -> (String,String) with ("fieldB","undefined"/"Nothing"/""/whatever)
The problem is that there may be 50 fields (my example was too simple, sorry). So I want precisely to avoid 'Just' and 'Nothing', because I want to be able to say : graph = AttrGraphDot {color = Blue} without having to name the 49 other fields. Field labels seem really adequate to do this, and by having defined the type Color with Red | Blue | ... there will be a compile-time check on the correctness of the value. This would be impossible with an ordinary implementation : [(String, String)] which will be verified only at run-time. But then I must be able to convert the field-labelled datatype to a list [(String, String)], depending on which labels have been provided. This is not so easy, especially since it is not possible to pattern-match against field labels, which are functions. Alain
ah, well than what you probably want is a default value for your fields. while not directly supported, it can easily be simulated as follows. data Foo = Foo { fieldA :: Maybe String, fieldB :: Maybe Int, fieldC :: Maybe String} foo = Foo {fieldA = Nothing, fieldB = Nothing, fieldC = Nothing} now what you can do is x = foo {fieldA = Just "hasFieldA"} y = foo {fieldB = Just 34} by using 'foo' rather than Foo you get your 'default' nothing values for everything not specified. John On Mon, May 26, 2003 at 11:50:27PM +0200, Alain Cremieux wrote:
The problem is that there may be 50 fields (my example was too simple, sorry). So I want precisely to avoid 'Just' and 'Nothing', because I want to be able to say : graph = AttrGraphDot {color = Blue} without having to name the 49 other fields. Field labels seem really adequate to do this, and by having defined the type Color with Red | Blue | ... there will be a compile-time check on the correctness of the value. This would be impossible with an ordinary implementation : [(String, String)] which will be verified only at run-time. But then I must be able to convert the field-labelled datatype to a list [(String, String)], depending on which labels have been provided. This is not so easy, especially since it is not possible to pattern-match against field labels, which are functions.
-- --------------------------------------------------------------------------- John Meacham - California Institute of Technology, Alum. - john@foo.net ---------------------------------------------------------------------------
On Mon, 26 May 2003 23:50:27 +0200 Alain Cremieux <alcremi@pobox.com> wrote:
Derek Elkins wrote:
On Sun, 25 May 2003 23:28:02 +0200 Alain Cremieux <alcremi@pobox.com> wrote:
data UR = MkUR { fieldA :: Int, fieldB :: Int, fieldC :: String } deriving (Show)
and, for example, we have
testUR = MkUR {fieldA = 1} testUR' = MkUR {fieldA = 2, fieldB = 3, fieldC = "C"}
Now I want to write a function which transforms my datatype in [(String, String)] where a (key, value) element exists if the field is>present, and none if the field does not exist.
attrList :: UR -> [(String, String)] attrList u = al "fieldA" (fieldA u) ++ al "fieldB" (fieldB u) ++ al "fieldC" (fieldC u)
al :: (Show a) => String -> a -> [(String, String)] al fn fv = [(fn, show fv)]
(Wouldn't it make more sense to do attrList u = [al "fieldA" (fieldA u), al ...] with al :: ... -> (String,String)?)
The idea is that the list may be empty, thus the choice of a list of pairs instead of a simple pair
But al (obviously) will never make an empty list. Also below Maybe (String,String) serves the same purpose. You use Maybe when you want to return 0 or 1 thing, and lists when you want to return 0 or many.
Of course, as written, "attrList testUR'" succeeds and "attrList testUR" fails (Missing field in record construction Main.fieldB) I need to match against undefined, which is impossible.
So reify undefined.
How can I do that ? Can you give me an example ?
That's what the Nothing constructor does.
Is there a solution (probably involving irrefutable patterns, ~) ?
You want values that may or may not be there. The standard solution is the Maybe type. Assuming you don't want to print out, "Just \"C\"", you can either make your own type with your own instance of show, or use a showValue function in al. The latter is likely preferable as there are quite a few utility functions for the Maybe type already and it's more familiar. You can define al with type ... -> Maybe (String,String) and attrList would just be catMaybes over a list of them, assuming you want attrList(MkUR (Just 5) Nothing (Just "Hello")) to give you[("fieldA","5"),("fieldC","\"Hello\"")] otherwise al can be ... ->(String, Maybe String) and you'd change show fv to fmap show fv, or just... -> (String,String) with ("fieldB","undefined"/"Nothing"/""/whatever)
The problem is that there may be 50 fields (my example was too simple, sorry). So I want precisely to avoid 'Just' and 'Nothing', because I want to be able to say : graph = AttrGraphDot {color = Blue} without having to name the 49 other fields. Field labels seem really adequate to do this, and by having defined the type Color with Red | Blue | ... there will be a compile-time check on the correctness of the value. This would be impossible with an ordinary implementation : [(String, String)] which will be verified only at run-time. But then I must be able to convert the field-labelled datatype to a list [(String, String)], depending on which labels have been provided. This is not so easy, especially since it is not possible to pattern-match against field labels, which are functions.
John Meacham gave you a good answer for the first part. And you certainly CAN pattern-match against field labels, e.g. foo ({ fieldA = Just 5, fieldB = Just x, fieldC = Nothing }) = x foo ({ fieldA = Just x }) = 0
participants (3)
-
Alain Cremieux -
Derek Elkins -
John Meacham