我在haskell中有一个系统,它使用Data.Dynamic和Type.Reflection来执行推理和计算。我希望能够随机生成动态数据。
当类型已知时,生成动态数据很容易。
goo :: SomeTypeRep -> IO (Dynamic)
goo str = case tyConName . someTypeRepTyCon $ str of
"Int" -> return . toDyn . randomRIO $ (-20, 100::Int)
"Bool" -> return . toDyn . randomRIO $ (True, False)
_ -> error "no chance"
但在处理元组时,为每种类型设置一个新行是不切实际的。
有没有办法将n动态组合成一个元组?或者是否有另一种动态生成元组的方法?
答案 0 :(得分:3)
通常在使用Type.Reflection
时,您希望将量化保留为"迟到"尽可能。考虑到这一点,以下似乎有效:
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE GADTs #-}
import Control.Applicative
import Data.Dynamic
import System.Random
import Type.Reflection
goo :: TypeRep a -> IO a
goo tr = case tr of
App (App comma a) b | Just HRefl <- eqTypeRep (typeRep @(,)) comma
-> liftA2 (,) (goo a) (goo b)
_ | Just HRefl <- eqTypeRep (typeRep @Int) tr -> randomRIO (-20, 100)
| Just HRefl <- eqTypeRep (typeRep @Bool) tr -> randomIO
| otherwise -> fail "dunno lol"
您可能会反对要使用现有的Dynamic
并生成一个新的,匹配的,随机的,并且这不起作用:
gooBad :: Dynamic -> IO Dynamic
gooBad d = case dynTypeRep d of
SomeTypeRep tr -> toDyn <$> goo tr
这是真的:SomeTypeRep
类型对TypeRep
的种类存在量化,这是不幸的,因为我们知道它是将代表一种类型*
。幸运的是,Data.Dynamic
在没有dynTypeRep
的情况下导出了足够的信息来自行完成:
gooDyn :: Dynamic -> IO Dynamic
gooDyn (Dynamic tr _) = Dynamic tr <$> goo tr