2011-04-21 25 views
6

Thời gian lập trình chung!Sử dụng Typeable để áp dụng một phần chức năng tại thời gian chạy (bất kỳ loại thời gian nào phù hợp)

Nếu tôi có một chức năng:

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

và một giá trị

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

Mà không biết tại thời gian biên dịch mà trong những lập luận của f giá trị v là loại phù hợp với (nếu có) , tôi có thể áp dụng một phần f cho v không? (sử dụng Typeable, Data, TH hoặc bất kỳ mẹo nào khác)

Hơi chắc chắn hơn, tôi có thể xây dựng hàm g (bên dưới) tại thời gian chạy không? Nó không thực sự phải là đa hình, tất cả các loại của tôi sẽ là đơn hình!

g :: (a1 -> a2 -> a3 -> a4 -> a5) -> a3 -> (a1 -> a2 -> a4 -> a5) 
g f v = \x y z -> f x y v z 

Tôi biết rằng, sử dụng Typeable (typeRepArgs cụ thể), v là đối số thứ 3 của f, nhưng điều đó không có nghĩa là tôi có một cách để một phần áp dụng f.

Mã của tôi có lẽ sẽ giống như sau:

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 

Có điều gì mà có thể thực hiện magicApplyFunction?

EDIT: Cuối cùng tôi đã trở lại để chơi với điều này. Chức năng ma thuật áp dụng là:

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 
+0

Không có gì sai với ** g **, theo như tôi thấy, và tính đa hình cũng không quan trọng. Cũng như bạn có thể sử dụng lật mọi lúc bạn có một hàm và đối số thứ 2, bạn biết đấy. – Ingo

+0

Nhưng tôi không có thời gian biên dịch! Làm thế nào tôi có thể tạo ra nó trong thời gian chạy? IIRC, tôi không thể chuyển các chức năng qua lại từ/gợi ý –

+0

Viết hàm để áp dụng nó thông qua thứ không phải là vấn đề - vấn đề là loại giá trị bạn nhận được (Dynamic/Box) là, bạn nhận ra, lựa chọn duy nhất của bạn. – sclv

Trả lời

2

Tôi sẽ không viết toàn bộ giải pháp ở đây bây giờ, nhưng tôi chắc chắn điều này có thể được thực hiện hoàn toàn với Data.DynamicTypeable. Nguồn tin cho dynApplyfunResultTy nên cung cấp các yếu tố chính:

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 

Để giữ cho mọi thứ đơn giản, tôi muốn có type Box = (Dynamic, [Either TypeRep Dynamic]). Sau đó bắt đầu như một danh sách các typereps của các đối số. magicApply sẽ tìm TypeRep khớp đầu tiên trong hộp và thay thế Dynamic của giá trị. Sau đó, bạn có thể có một extract được gán Box mà tất cả các đối số đã được ảo hóa, thực sự thực hiện các cuộc gọi dynApply để tạo kết quả động.

+0

Đây không phải là chỉ kiểm tra động rằng 'x' là loại chính xác cho đối số đầu tiên của' f' (không đảo ngược/sắp xếp lại đối số)? Nếu 'f :: Int -> Double -> Bool' và' x :: Double' thì tôi muốn kết hợp 'f' và' x' để lấy 'h :: Int -> Bool'. Tôi đã bỏ lỡ câu trả lời của bạn chưa? –

+0

@TomMD đó là những gì dynApply và funResultTy làm. Chúng chỉ là sao chép/dán từ các định nghĩa thư viện. * Làm thế nào * họ làm điều đó cho thấy làm thế nào để trích xuất danh sách đầy đủ các đối số cho một chức năng, mà lần lượt có thể được sử dụng để thực hiện các giải pháp tôi phác thảo bên dưới mã đó. – sclv

+0

Ah, tôi thấy quan điểm của bạn. Tôi sẽ chơi với điều này một chút - cảm ơn! –

1

Hm .. Chỉ có thể nhập? Làm thế nào về OverlappingInstances cũ tốt?

{-# 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' 
Các vấn đề liên quan