Tho*_*son 6 haskell generic-programming
通用编程时间!
如果我有一个功能:
f :: a1 -> a2 -> a3 -> ... -> an
Run Code Online (Sandbox Code Playgroud)
和一个价值
v :: aX -- where 1 <= x < n
Run Code Online (Sandbox Code Playgroud)
不知道在编译的时候,其中的参数f值v是正确的类型(如果有的话),我可以部分地适用f于v?(使用Typeable,Data,TH或任何其他技巧)
稍微坚定一点,我可以g在运行时构建函数(下面)吗?它实际上不必是多态的,我的所有类型都将是单态的!
g :: (a1 -> a2 -> a3 -> a4 -> a5) -> a3 -> (a1 -> a2 -> a4 -> a5)
g f v = \x y z -> f x y v z
Run Code Online (Sandbox Code Playgroud)
我知道,使用Typeable(typeRepArgs特别是),v是第三个参数f,但这并不意味着我有办法部分应用f.
我的代码可能看起来像:
import Data.Typeable
data Box = forall a. Box (TyRep, a)
mkBox :: Typeable a => a -> Box
mkBox = (typeOf a, a)
g :: Box -> Box -> [Box]
g (Box (ft,f)) (Box (vt,v)) =
let argNums = [n | n <- [1..nrArgs], isNthArg n vt ft]
in map (mkBox . magicApplyFunction f v) argNums
isNthArg :: Int -> TyRep -> TyRep -> Bool
isNthArg n arg func = Just arg == lookup n (zip [1..] (typeRepArgs func))
nrArgs :: TyRep -> Int
nrArgs = (\x -> x - 1) . length . typeRepArgs
Run Code Online (Sandbox Code Playgroud)
有什么可以实现的magicApplyFunction吗?
编辑:我终于回到了玩这个.魔术应用功能是:
buildFunc :: f -> x -> Int -> g
buildFunc f x 0 = unsafeCoerce f x
buildFunc f x i =
let !res = \y -> (buildFunc (unsafeCoerce f y) x (i-1))
in unsafeCoerce res
Run Code Online (Sandbox Code Playgroud)
我现在不打算在这里写出整个解决方案,但我确信这可以纯粹使用Data.Dynamic和 来完成Typeable。dynApply和 的来源funResultTy应提供关键要素:
dynApply :: Dynamic -> Dynamic -> Maybe Dynamic
dynApply (Dynamic t1 f) (Dynamic t2 x) =
case funResultTy t1 t2 of
Just t3 -> Just (Dynamic t3 ((unsafeCoerce f) x))
Nothing -> Nothing
funResultTy :: TypeRep -> TypeRep -> Maybe TypeRep
funResultTy trFun trArg
= case splitTyConApp trFun of
(tc, [t1,t2]) | tc == funTc && t1 == trArg -> Just t2
_ -> Nothing
Run Code Online (Sandbox Code Playgroud)
为了简单起见,我会type Box = (Dynamic, [Either TypeRep Dynamic])。后者从参数的类型代表列表开始。magicApply会在框中查找第一个匹配的 TypeRep 并替换该Dynamic值的 。然后,您可以拥有一个extract给定的 a Box,所有参数都已被神奇地应用到 a ,实际执行调用dynApply以产生动态结果。