I'm having problems with my template generator. I have everything working except for the "flen" function which I'm faking for now: http://lava.net/~newsham/x/jethr0/ The directory has 4 source files (with or without .txt extensions for your browsing enjoyment): ByteContainer.lhs - defining my classes IP.lhs - defining my test data type Gen.lhs - defining my TH generator tst.lhs - my test case. You can see it go by running "ghc -c -fth -ddump-splices tst.lhs". The problem: flen should compute and return the size of each field. Concretely: flen ("Word8",_,_) should compute "containerLength newWord8" flen ("Word16",_,_) should compute "containerLength newWord16" flen ("IP",_,_) should compute "containerLength newIP" flen (n,_,_) should compute "containerLength" of ("new"++n) The flen function is used during template generation, and needs to know the integer length while expanding the template (ie. flen doesnt generate anything). Is this possible? Tim Newsham http://www.lava.net/~newsham/
Hello Tim, Friday, January 20, 2006, 12:51:39 PM, you wrote: TN> flen ("Word8",_,_) should compute "containerLength newWord8" TN> flen ("Word16",_,_) should compute "containerLength newWord16" TN> flen ("IP",_,_) should compute "containerLength newIP" TN> flen (n,_,_) should compute "containerLength" of ("new"++n) first, `flen` must be monadic computation because it needs access to the Q monad second, define it recursively: flen t | t=='Word8 = return 1 flen t | t=='Word16 = return 2 flen t = do -- Get information about type t, assuming it is declared as -- one-constructor "data", such as "data T = T Int16 Word32" TyConI (DataD _ _ _ [constructor] _) <- reify t -- Get types of individual fields let fields = fieldTypes constructor -- Calculate len for each field flens <- mapM flen fields return (sum flens) ... i attached the finally debugged version together with test you can't run at compile time your run-time function `containerLength`, so you just need to arrange these calcultaions yourself, using `reify` to get fieldlist for each data type
I have a record name and a field name (and a field type name), all as strings.
passing them as the strings is not good idea. it's better to keep them as Name values (Name type is defined in TH) -- Best regards, Bulat mailto:bulatz@HotPOP.com
first, `flen` must be monadic computation because it needs access to the Q monad
second, define it recursively:
flen t | t=='Word8 = return 1 flen t | t=='Word16 = return 2 flen t = do -- Get information about type t, assuming it is declared as -- one-constructor "data", such as "data T = T Int16 Word32" TyConI (DataD _ _ _ [constructor] _) <- reify t -- Get types of individual fields let fields = fieldTypes constructor -- Calculate len for each field flens <- mapM flen fields return (sum flens)
Thank you. This makes a lot of sense. My only problem with this is the declarations of the base types in the generator: flen t | t == 'Word8 = return 1 This precludes someone from adding other base types without modifying the generator.
I have a record name and a field name (and a field type name), all as strings.
passing them as the strings is not good idea. it's better to keep them as Name values (Name type is defined in TH)
*nod* The strings were my first step to get things working before I explore more TH syntax.
Bulat mailto:bulatz@HotPOP.com
Thank you for your insights. Tim Newsham http://www.lava.net/~newsham/
Hello Tim, Friday, January 20, 2006, 8:35:03 PM, you wrote: TN> Thank you. This makes a lot of sense. My only problem with this is TN> the declarations of the base types in the generator: TN> flen t | t == 'Word8 = return 1 TN> This precludes someone from adding other base types without modifying TN> the generator. as i initially understand, you are planned to use this lib only in your own app? anyway, this depends on how other things will be arranged. adding new type require some other support besides of modifying `flen`. how your imagine the scenario of this process? on the other side, sizes for enumerations can be calculated. number of other simple types are limited. all other types are complex, i.e. their sizes is a function of sized of types they contain on the third side :) you can try to rewrite instantiation so that it will not need to know these sizes at compile-time:
data IP = IP Word16 Word32 Word64
instance ByteContainer IP containerLength (IP x1 x2 x3) = (containerLength x1)+ (containerLength x2)+ (containerLength x3)
makeContainer b = IP (makeContainer (Slice b 0)) (makeContainer (Slice b offset1)) (makeContainer (Slice b offset2)) where offset1 = containerLength newWord16 offset2 = offset1+containerLength newWord32
getByteAt (IP x0 x1 x2) n | n >= offset2 = getByteAt x2 (n-offset2) | n >= offset1 = getByteAt x1 (n-offset1) | otherwise = getByteAt x0 n
where offset1 = containerLength newWord16 offset2 = offset1+containerLength newWord32
? the only problem is what TH can't generate INLINE pragmas, so this code can work rather slow btw, newXX operations may be better to include in the class definition:
class ByteContainer b where new :: b .....
-- Best regards, Bulat mailto:bulatz@HotPOP.com
participants (2)
-
Bulat Ziganshin -
Tim Newsham