On Sun, Oct 10, 2010 at 10:51 PM, Alexander Solla <[email protected]> wrote:
> Is there anyway to instruct GHC (and maybe other compilers) to compute these
> maps statically? Are GHC and the other compilers smart enough to do it
> automatically? Although the list isn't huge, I would still rather get rid of
> the O(2*n) operation of turning it into maps at run-time. (Especially since
> some later list encodings like these might be enormous) What should I be
> looking into?

You may use Template Haskell and forget about the 'Data.Map's entirely =).

I've attached a proof-of-concept code that turns

  list :: [(a,b)]
  list = [(x1,y1), (x2, y2), ..., (xn, yn)]

into two functions (you can choose the names)

  fromAtoB :: a -> b
  fromAtoB x1 = y1
  fromAtoB x2 = y2
  ...
  fromAtoB xn = yn

  fromBtoA :: b -> a
  fromBtoA y1 = x1
  ...
  fromBtoA yn = xn

but with the arguments tranformed to patterns.

Compiling a test module:

$ ghc -ddump-splices -c ModuleWithFunctions.hs
Loading package ghc-prim ... linking ... done.
Loading package integer-gmp ... linking ... done.
Loading package base ... linking ... done.
Loading package ffi-1.0 ... linking ... done.
Loading package array-0.3.0.1 ... linking ... done.
Loading package containers-0.3.0.0 ... linking ... done.
Loading package pretty-1.0.1.1 ... linking ... done.
Loading package template-haskell ... linking ... done.
ModuleWithFunctions.hs:1:0:
    ModuleWithFunctions.hs:1:0: Splicing declarations
        bimap
          "map_country_to_country_code"
          "map_country_code_to_country"
          countries_and_iso_country_codes
      ======>
        ModuleWithFunctions.hs:8:2-98
        map_country_to_country_code Afghanistan
                                      = ISOCountryCode AF AFG (NC 4)
        map_country_to_country_code AlandIslands
                                      = ISOCountryCode AX ALA (NC 248)
        map_country_to_country_code Albania = ISOCountryCode AL ALB (NC 8)
        map_country_to_country_code Zimbabwe
                                      = ISOCountryCode ZW ZWE (NC 716)
        map_country_code_to_country ISOCountryCode AF AFG NC 4
                                      = Afghanistan
        map_country_code_to_country ISOCountryCode AX ALA NC 248
                                      = AlandIslands
        map_country_code_to_country ISOCountryCode AL ALB NC 8 = Albania
        map_country_code_to_country ISOCountryCode ZW ZWE NC 716 = Zimbabwe


So two functions were spliced into your code with explicit pattern
matches.  I don't know how efficient is the code that GHC generates
for functions with many patterns.  Now, testing them:

$ ghci
GHCi, version 6.12.3: http://www.haskell.org/ghc/  :? for help
Loading package ghc-prim ... linking ... done.
Loading package integer-gmp ... linking ... done.
Loading package base ... linking ... done.
Loading package ffi-1.0 ... linking ... done.
:Prelude> :l Module
[4 of 4] Compiling Module           ( Module.hs, interpreted )
Ok, modules loaded: Module, ModuleWithData, ModuleWithFunctions, Template.
*Module> :bro Module
data Country = Afghanistan | AlandIslands | Albania | Zimbabwe
data ISOCountryCode = ISOCountryCode TwoCode ThreeCode NumCode
data NumCode = NC Int
data ThreeCode = AFG | ALA | ALB | ZWE
data TwoCode = AF | AX | AL | ZW
countries_and_iso_country_codes :: [(Country, ISOCountryCode)]
isoNumericCode :: Int -> NumCode
map_country_code_to_country :: ISOCountryCode -> Country
map_country_to_country_code :: Country -> ISOCountryCode
*Module> map_country_to_country_code Albania
Loading package array-0.3.0.1 ... linking ... done.
Loading package containers-0.3.0.0 ... linking ... done.
Loading package pretty-1.0.1.1 ... linking ... done.
Loading package template-haskell ... linking ... done.
ISOCountryCode AL ALB (NC 8)
*Module> map_country_code_to_country $ ISOCountryCode AL ALB (NC 8)
Albania

Cheers! =)

-- 
Felipe.
{-# LANGUAGE DeriveDataTypeable #-}

module ModuleWithData where

import Data.Data
import Data.Typeable

data Country = Afghanistan | AlandIslands | Albania | Zimbabwe
               deriving (Data, Eq, Ord, Show, Typeable)

data ISOCountryCode = ISOCountryCode TwoCode ThreeCode NumCode
                      deriving (Data, Eq, Ord, Show, Typeable)

data TwoCode = AF | AX | AL | ZW
               deriving (Data, Eq, Ord, Show, Typeable)

data ThreeCode = AFG | ALA | ALB | ZWE
                 deriving (Data, Eq, Ord, Show, Typeable)

data NumCode = NC Int
               deriving (Data, Eq, Ord, Show, Typeable)

isoNumericCode :: Int -> NumCode
isoNumericCode = NC

countries_and_iso_country_codes :: [ (Country, ISOCountryCode) ]
countries_and_iso_country_codes =
        [ (Afghanistan,  ISOCountryCode AF AFG (isoNumericCode 004))
        , (AlandIslands, ISOCountryCode AX ALA (isoNumericCode 248))
        , (Albania,      ISOCountryCode AL ALB (isoNumericCode 008))
        , (Zimbabwe,     ISOCountryCode ZW ZWE (isoNumericCode 716))
        ]
{-# LANGUAGE TemplateHaskell #-}

module ModuleWithFunctions where

import ModuleWithData
import Template

$(bimap "map_country_to_country_code" "map_country_code_to_country" countries_and_iso_country_codes)
module Template (bimap, map') where

import Control.Monad
import Data.Data
import Language.Haskell.TH
import Language.Haskell.TH.Quote

bimap :: (Data a, Data b) => String -> String -> [(a,b)] -> Q [Dec]
bimap name1 name2 xs = do m1 <- map' name1 xs
                          m2 <- map' name2 [(b,a) | (a,b) <- xs]
                          return [m1,m2]

map' :: (Data a, Data b) => String -> [(a,b)] -> Q Dec
map' name xs = liftM (FunD $ mkName name) (mapM mkClause xs)
    where
      mkClause (a,b) = do
        a_pat <- dataToPatQ (const Nothing) a
        b_exp <- dataToExpQ (const Nothing) b
        return $ Clause [a_pat] (NormalB b_exp) []
module Module
    (module ModuleWithData
    ,module ModuleWithFunctions) where

import ModuleWithData
import ModuleWithFunctions
_______________________________________________
Haskell-Cafe mailing list
[email protected]
http://www.haskell.org/mailman/listinfo/haskell-cafe

Reply via email to