
Hello, all! I need to create objects like this data Object = MyObject { param1, param2, param3 :: String } from the input file param_1_param1=value11 param_2_param1=value21 param_2_param2=value22 param_1_param3=value13 param_2_param3=value23 param_1_param2=value12 so general pattern of recognizing parameter name and value is param_{id}_{property name}={property value} so I need to create function
parseDataFile :: [String] -> [Object]
For now I can think on splitting the task into 2 functions
groupSameObjectParameters :: [String] -> [[String]]
which will group the lines with same id into a list, and then apply function
createObject :: [String] -> Object
so overall solution will be
parseDataFile :: [String] -> [Object] parseDataFile = map createObject . groupSameObjectParameters
however I have no neat idea about how to create instance of MyObject - I need to supply all of parameters to the constructor at once. Also I don't like the idea of rearranging list first and then create objects from another list, because the list can be relatively large. In imperative programming with mutable objects I would create an array, then for each line get the id and try to find if there is the object in the array at 'id' index. If no - create one. Then set appropriate property from value. Is it possible to do something similar in Haskell? Thank you in advance! -- Eugene N Dzhurinsky

Hi Eugene You don't need to supply all the arguments to a constructor at once: makeWithOne :: String -> (String -> String -> Object) makeWithOne s1 = \s2 s3 -> Object s1 s2 s3 -- or even: -- makeWithOne s1 = Object s1 This builds a higher-order function that can be applied later to two Strings to finally make the Object. Best wishes Stephen

On Thu, May 13, 2010 at 04:43:26PM +0100, Stephen Tetley wrote:
Hi Eugene
You don't need to supply all the arguments to a constructor at once:
makeWithOne :: String -> (String -> String -> Object) makeWithOne s1 = \s2 s3 -> Object s1 s2 s3
-- or even: -- makeWithOne s1 = Object s1
This builds a higher-order function that can be applied later to two Strings to finally make the Object.
Hello, Stephen! Well, that's true, but I don't really know the order of incoming data. So for constructor MyObject { prop1, prop2, prop3 :: String } there can be the cases of order prop1 prop2 prop3 prop3 prop2 prop1 prop1 prop3 prop2 ... so I may need to initialize prop1, then prop3, and finally prop2 to make instance of MyObject. And similarly for another cases. I don't see any easy solution for now except sort name-value pairs in some pre-defined order, and then use something like
props :: [(String,String)] result = MyObject (props' !! 0) (props' !! 1) (props' !! 2) where props' = map snd props
which looks ugly and involves some additional calculations for sorting. -- Eugene Dzhurinsky

Hi Eugene Is something like this close to what you want: For example this builds an object with ordered strings... makeOrdered :: String -> String -> String -> Object makeOrdered a b c = let (s,t,u) = sort3 (a,b,c) in Object s t u Alternatively you could build the with the Strings as they appear in the input then use an Object 'transformer' - a function from Object to Object (fun :: Object -> Object), e.g orderObject :: Object -> Object orderObject (Object a b c) = Object s t u where s = min3 a b c t = med3 a b c u = max3 a b c demo1 = orderObject (Object "4" "6" "1") Support code -- inefficient, but I had max3, etc to hand... sort3 :: Ord a => (a,a,a) -> (a,a,a) sort3 (a,b,c) = (s,t,u) where s = min3 a b c t = med3 a b c u = max3 a b c -- Or without the intermediate triple: -- -- sort3 :: Ord a => a -> a -> a -> (a,a,a) -- sort3 a b c = (s,t,u) -- where -- s = min3 a b c -- t = med3 a b c -- u = max3 a b c -- | max of 3 max3 :: Ord a => a -> a -> a -> a max3 a b c = max (max a b) c -- | min of 3 min3 :: Ord a => a -> a -> a -> a min3 a b c = min (min a b) c -- | median of 3 med3 :: Ord a => a -> a -> a -> a med3 a b c = if c <= x then x else if c > y then y else c where (x,y) = order a b order p q | p <= q = (p,q) | otherwise = (q,p)

Hi. Stephen Tetley wrote:
Hi Eugene
Is something like this close to what you want:
For example this builds an object with ordered strings...
makeOrdered :: String -> String -> String -> Object makeOrdered a b c = let (s,t,u) = sort3 (a,b,c) in Object s t u
Or just: makeOrdered a b c = let (s:t:u:_) = sort [a, b, c] in Object s t u (no support code required)

On Thu, May 13, 2010 at 07:14:25PM +0100, Stephen Tetley wrote:
Hi Eugene
Is something like this close to what you want:
Not really. First of all, there're many properties, not 3. So it may end up with plenty of support (boilerplate) code. Also, names of these parameters are not sortable. Of course I could make these names as another data type with deriving from Eq/Ord - but that increase complexity as well. Original idea was 1) create Array 2) if line "param_N_name=value" appear, then 2.1) try to take object N from array 2.2) if no object exists - then create one 2.3) set the property "name" to "value" 2.4) put resulting object back into array 3) take next line and go to 2 so if it is possible to have partially initialized objects in Haskell, then this approach should work. If now - well, then replace creation of object with adding name/value pair to an array. And then create objects from those arrays. -- Eugene Dzhurinsky

On Thursday 13 May 2010 20:43:44, Eugeny N Dzhurinsky wrote:
On Thu, May 13, 2010 at 07:14:25PM +0100, Stephen Tetley wrote:
Hi Eugene
Is something like this close to what you want:
Not really. First of all, there're many properties, not 3. So it may end up with plenty of support (boilerplate) code.
Also, names of these parameters are not sortable. Of course I could make these names as another data type with deriving from Eq/Ord - but that increase complexity as well.
Original idea was
1) create Array 2) if line "param_N_name=value" appear, then 2.1) try to take object N from array 2.2) if no object exists - then create one 2.3) set the property "name" to "value" 2.4) put resulting object back into array 3) take next line and go to 2
so if it is possible to have partially initialized objects in Haskell,
If the fields aren't strict, there's no problem having data MyObject = MyObject { param1, param2, param3 :: String } emptyObject = MyObject undefined undefined undefined -- Boilerplate code, but you can let that write the computer for you update :: String -> MyObject -> String -> MyObject update "param1" obj val = obj{param1 = val} update "param2" obj val = obj{param2 = val} update "param3" obj val = obj{param3 = val} update _ obj _ = obj and start from emptyObject, updateing the fields as they come (if the fields aren't all Strings, read or parse the value). import qualified Data.Map as Map import Data.List (foldl') -- break all lines into: -- object ID (N) -- field to be set (name) -- value breakUpLine :: String -> (Int, String, String) -- construct a map ID -> object from the lines of the file construct :: [String] -> Map Int MyObject construct = foldl' updateMap (Map.empty) where updateMap mp (i, fld, val) = case Map.findWithDefault emptyObject i mp of obj -> Map.insert i (update fld obj val) mp
then this approach should work. If now - well, then replace creation of object with adding name/value pair to an array. And then create objects from those arrays.
participants (5)
-
Daniel Fischer
-
Eugene Dzhurinsky
-
Eugeny N Dzhurinsky
-
Steffen Schuldenzucker
-
Stephen Tetley