[Haskell-cafe] introspection | meta data

Crypt Master cryptmaster at hotmail.com
Thu Aug 5 15:53:18 EDT 2004

>Can you name these fields?  If so, haskell has (sorta clumsy) named 
>and you can select and update fields by name, and you can replace
>'setSFField 3 sf x' with 'sf {somefield=x}'

I did think of this, but unfortunatly my algorithm cant use names (without 
hard coding all possible combinations )

> > So what is the general haskell approach to this type of 
> > data problem... ?

>A C array of pointers maps closest to a MutableArray, which is mostly a 
>with different performance.  Unless you're casting pointers, in which case
>Dynamic types or the Generic stuff is maybe what you want.  Or a redesign 

I looked at haskell arrays, but since I cant point to an element in my tuple 
it wont work out. The ANSI C use of arrays is a really simple (but nasty) 
way to provide a means for me to loop over a fixed struct record. The 
Generic library looks super, only had time to browse some slides thus far, 
but will defiantly try understand that.

As for a redesign and
>Others have given good answers for this, but I suspect you may have chosen 
>wrong data structure...

I would be keen on any ideas you have on how to design this in haskell. 
Learning to think in haskell is after all the goal :-) The example below is 
trivial and real world, both reasons why I chose to use it.

Any comments welcome, none expected :-)



I idea is to perform a search over a number fields in a hierachical fashion 
where each field can have a wild card. The real world example is printer 
selection. In a multi-national company all users tend to be on one (or a 
few) central servers, but require there printouts to come to them locally 
whereever they are. Users typically range in 1000s and so "by user" 
defintions are out.

Simplified Search fields:

Environemnt, Users, Report, Version, Host      Printer
----------------------------------------------------------     ----------

The "most" speicific field is host on the right with it becomming more 
general moving to towards the left.

Setup data could choose to override all of report "RPT1" version "Ver1" to 
Printer "Bobs Printer"

*ALL, *ALL, "RPT1", "Ver1", "*ALL",  "Bobs Printer"

but Simon may be an exception, then a record could be added like so:

*ALL, "SIMON", "RPT1", "Ver1", *ALL, "Simons Printer"

This record would be found first for simon, but former found found for 
everyone else.

A search starts from fully specific data i.e no wild cards.

The basic algortihm I worked out is:

1. Search setup data
2. If no record found
   2a:  Set current field to most specific field (host in this case)
   2b: Toggle current field  ( if Wildcard then make it value, if value make 
it wildcard )
   2c:  if current field is *ALL goto 1 above (we stop here to perform a 
search on the current permutation)
   2d: Loop to 2b until no more fields

And my haskell working proto type is this:

module Main where

           -- Env       User     Report     Version     Host    Printer
egdata1 = [(("PD7334EU", "*ALL",  "*ALL",    "*ALL",     "*ALL"), "Default 
           (("PD7334EU", "USER1", "*ALL",    "*ALL",     "*ALL"), 
           (("PD7334EU", "USER2", "Report1", "Version1", "*ALL"), 
           (("PD7334EU", "*ALL",  "Report2", "*ALL",     "*ALL"), 

type SearchFilter = (String, String, String, String, String)
type Record       = (SearchFilter, String)

findPrinter :: String -> String -> String -> String -> String -> [Record]
-> String
findPrinter env user report version host printerdata =
      findPrinter' sf sf printerdata
        sf = (env, user, report, version, host)

findPrinter' :: SearchFilter -> SearchFilter -> [Record] -> String
findPrinter' ("*ALL", "*ALL", "*ALL", "*ALL", "*ALL") _ _     = ""
findPrinter' sf origsf printerdata
    | printer == ""   =  findPrinter' (toggle sf origsf 5) origsf
    | otherwise       =  printer
          printer = searchPrinter sf printerdata

searchPrinter :: SearchFilter -> [Record] -> String
searchPrinter _ [] = ""
searchPrinter sf ((x,p):xa)
    | sf == x    = p
    | otherwise  = searchPrinter sf xa

toggle :: SearchFilter -> SearchFilter -> Int -> SearchFilter
toggle sf origsf 0 = sf
toggle sf origsf n
    | newValue == "*ALL"   = newSF
    | otherwise            = toggle newSF origsf (n-1)
       newValue = toggleField (getSFField n sf) (getSFField n origsf)
       newSF    = setSFField n sf newValue

toggleField :: String -> String -> String
toggleField "*ALL" x = x
toggleField _ _ = "*ALL"

getSFField :: Int -> SearchFilter -> String
getSFField 1 (x,_,_,_,_) = x
getSFField 2 (_,x,_,_,_) = x
getSFField 3 (_,_,x,_,_) = x
getSFField 4 (_,_,_,x,_) = x
getSFField 5 (_,_,_,_,x) = x

setSFField :: Int -> SearchFilter -> String -> SearchFilter
setSFField 1 (a,b,c,d,e) f = (f,b,c,d,e)
setSFField 2 (a,b,c,d,e) f = (a,f,c,d,e)
setSFField 3 (a,b,c,d,e) f = (a,b,f,d,e)
setSFField 4 (a,b,c,d,e) f = (a,b,c,f,e)
setSFField 5 (a,b,c,d,e) f = (a,b,c,d,f)

main = putStrLn (findPrinter "PD7334EU" "USER2" "Report2" "Version3"
"SomeHost" egdata1)

Add photos to your messages with MSN 8. Get 2 months FREE*. 

More information about the Haskell-Cafe mailing list