Reputation: 3670
There are lots of Haskell
tutorials on parsing sources into an AST, AST rewrites, AST evaluations but not on mapping between two ASTs. Is there a "canonical" way to implement transformFoo2Bar
in Haskell
?
type FooIdentifier = String
data Foo = Foo FooIdentifier [FooMethod] deriving (Show)
data FooMethod = FooMethod FooIdentifier [FooExpression] deriving (Show)
data FooExpression = FooAB FooIdentifier FooIdentifier | FooZ FooIdentifier deriving (Show)
type BarIdentifier = String
type BarLabel = String
data Bar = Bar BarIdentifier [BarExpression] deriving (Show)
data BarExpression = BarA BarIdentifier BarIdentifier
| BarB BarIdentifier BarIdentifier | BarZ BarIdentifier deriving (Show)
--
-- transformFoo2Bar [Foo "foo" [FooMethod "foo1" [FooAB "a" "b", FooZ "z"], FooMethod "foo2" [FooZ "z"]]]
--
-- to evaluate to
--
-- [Bar "foo_foo1" [BarA "a" "b", BarB "a" "b", BarZ "z"], Bar "foo_foo2" [BarZ "z"]]
--
transformFoo2Bar :: [Foo] -> [Bar]
transformFoo2Bar = undefined
Similar to code compilation, but instead of emitting compiled code, keep the result as AST.
Also could some of these mappings be reused as reverse mapping?
Thanks
Upvotes: 1
Views: 318
Reputation: 6610
The highly uncanonical way to do this is to change the definition of BarExpression around to
data BarExpression = BarB BarIdentifier | BarA BarIdentifier BarIdentifier deriving (Show)
so that it's not only structurally similar to FooExpression
, but also has the same runtime representation.
Then you can use Unsafe.Coerce.unsafeCoerce
:
fe1 = FooA "a"
fe2 = FooB "x" "y"
fm1= FooMethod "meth1" [fe1,fe2]
foo1 = Foo "foo" [fm1]
Which allows you to do
ghci> unsafeCoerce foo1 :: Bar
Bar "foo" [BarProc "meth1" [BarB "a",BarA "x" "y"]]
<font size+=1000 color="red"><blink>
</blink></font>
I don't recommend doing this at all as it will put your eternal soul in peril, will break unexpectedly as soon as you look at it and in very, very bad ways (if you don't swap BarExpression
this example starts causing segfaults :-) but it works for this particular use case.
Alternatively, you could get rid of one of the isomorphic types; is there a reason why you can't do this?
Upvotes: 1