Dynamicな事をしだした
RubyからHaskellのコードに変換(別にRubyじゃなくてDynamicな言語で)するのってどうしてやろうとかいう事を考えていたので、愚直にData.Dynamicはどうだろうかとか。
HaskellのData.Dynamicは、取りあえず値をDynamicで包んで、後で取り出してあげましょうという感じですが、良い感じで駄目な気がする。
Prelude> :m Data.Dynamic Prelude Data.Dynamic> toDyn "hoge" Prelude Data.Dynamic> fromDyn (toDyn "hoge") "default-value" "hoge" *Main> let hoge (Just a) = a *Main> hoge (fromDyna (toMDyn "hoge")) ++ "bar" "hogebar" *Main> hoge (fromDyna (toMDyn "hoge")) + 2 *** Exception: <interactive>:1:4-20: Non-exhaustive patterns in function hoge
http://haskell.org/ghc/docs/latest/html/libraries/base/Data-Dynamic.html
ここを見ればわかる話なんですけど。
fromDynの中身は
fromDyn (Dynamic t v) def | typeOf def == t = unsafeCoerce v | otherwise = def
Dynamicは、型と値を保持しておくdata constructorで、その定義は
data Dynamic = Dynamic TypeRep Obj #ifdef __GLASGOW_HASKELL__ type Obj = Any -- Use GHC's primitive 'Any' type to hold the dynamically typed value. -- -- In GHC's new eval/apply execution model this type must not look -- like a data type. If it did, GHC would use the constructor convention -- when evaluating it, and this will go wrong if the object is really a -- function. Using Any forces GHC to use -- a fallback convention for evaluating it that works for all types.
こんな感じになってくる。
が、私は日本人なのでアメリカ語とかは読めない、日本語でおk。取りあえず何でも受け取れる感じにしたいんだから、バッドノウハウで習得した次の様なのを入れる。
{-# LANGUAGE EmptyDataDecls,RankNTypes #-} {- MyAny1と同じ定義のAnyは、Data.Monoidの中にあって http://haskell.org/ghc/docs/6.8.3/html/libraries/base/Data-Monoid.html newtype Any Anyの定義がもう1つあるのは、 http://haskell.org/ghc/docs/6.8.3/html/libraries/base/GHC-Prim.html data Any a ただ後者の定義では上手く動かない。 -} data MyAny1 type MyAny2 = forall a . a
として、Data.Dynamicと全く同じですが
{-# LANGUAGE EmptyDataDecls,RankNTypes #-} -- import GHC.Base -- import Data.Dynamic -- import Data.Monoid import Data.Typeable import Unsafe.Coerce data MyAny1 type MyAny2 = forall a . a data MyDyn = MyDyn TypeRep MyAny2 toMDyn v = MyDyn (typeOf v) (unsafeCoerce v) -- 返す型の値がdefで決められるから、unsafeCoerceでそっちにcastされる fromDyn (MyDyn t v) def | typeOf def == t = unsafeCoerce v | otherwise = def -- 実行時に、どの型にキャストすべきかをunsafeCoerceに任せる fromDyna (MyDyn t v) = case unsafeCoerce v of r | t == typeOf r -> Just r | otherwise -> Nothing
formDynaの例は上に示してますが、例えば
Prelude Data.Char> :t ord ord :: Char -> Int Prelude Data.Char> ord 'a' 97 Prelude Data.Char> ord 0 <interactive>:1:4: No instance for (Num Char) arising from the literal `0' at <interactive>:1:4 Possible fix: add an instance declaration for (Num Char) In the first argument of `ord', namely `0' In the expression: ord 0 In the definition of `it': it = ord 0 Prelude Data.Char> ord (Unsafe.Coerce.unsafeCoerce 0) 0 Prelude Data.Char> ord (Unsafe.Coerce.unsafeCoerce 1) 1 Prelude Unsafe.Coerce> 1 + (unsafeCoerce 'A') 66 Prelude Unsafe.Coerce> "hoge" ++ (unsafeCoerce 1) "hoge"
なんかこの辺汚いなぁとか思わざるを得ませんでした。
そういえば、CleanにはDynamic型がどうこういうのをどこかで見たけど、あれはどうしているんだろう。