Использование Typeable для частичного применения функции во время выполнения (любое совпадение типов времени) - PullRequest
6 голосов
/ 21 апреля 2011

Общее время программирования!

Если у меня есть функция:

f :: a1 -> a2 -> a3 -> ... -> an

и значение

v :: aX   -- where 1 <= x < n

Не зная во время компиляции, какой из аргументов 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

Я знаю, что, используя 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

Есть ли что-нибудь, что может реализовать 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

Ответы [ 2 ]

2 голосов
/ 21 апреля 2011

Я не собираюсь сейчас писать полное решение здесь, но я уверен, что это можно сделать исключительно с 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

Для простоты, у меня будет type Box = (Dynamic, [Either TypeRep Dynamic]).Последний начинается как список типов аргументов.magicApply будет искать первый соответствующий TypeRep в поле и подставлять Dynamic значения.Тогда вы могли бы получить extract, который с учетом Box, к которому были применены все аргументы, фактически выполняет вызовы dynApply для получения результирующего динамического результата.

1 голос
/ 21 апреля 2011

Хм .. Только для ввода? Как насчет старых добрых экземпляров OverlappingInstances?

{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances, TypeFamilies,
UndecidableInstances, IncoherentInstances, ScopedTypeVariables #-}

class Magical a b c where
    apply :: a -> b -> c

instance (AreEqual a c e, Magical' e (a -> b) c r) => Magical (a -> b) c r where
    apply f a = apply' (undefined :: e) f a


class Magical' e a b c where
    apply' :: e -> a -> b -> c

instance (r ~ b) => Magical' True (a -> b) a r where
    apply' _ f a = f a

instance (Magical b c d, r ~ (a -> d)) => Magical' False (a -> b) c r where
    apply' _ f c = \a -> apply (f a) c


data True
data False

class AreEqual a b r
instance (r ~ True) => AreEqual a a r
instance (r ~ False) => AreEqual a b r


test :: Int -> Char -> Bool
test i c = True

t1 = apply test (5::Int)
t2 = apply test 'c'
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...