के साथ फर्थ डीएसएल लिखने में परेशानी मुझे हाल ही में हास्केल ब्लॉग गतिविधि से प्रेरित किया गया है ताकि हास्केल में एक फर्थ-जैसी डीएसएल लिखने पर मेरा हाथ आ सकें। दृष्टिकोण मैं ले लिया है एक साथ सीधा और भ्रामक है:हास्केल में पंक्ति बहुलकता: "ट्रांसफॉर्मेशन"
{-# LANGUAGE TypeOperators, RankNTypes, ImpredicativeTypes #-}
-- a :~> b represents a "stack transformation"
-- from stack type "a" to stack type "b"
-- a :> b represents a "stack" where the top element is of type "b"
-- and the "rest" of the stack has type "a"
type s :~> s' = forall r. s -> (s' -> r) -> r
data a :> b = a :> b deriving Show
infixl 4 :>
सरल काम करने के लिए, यह काफी अच्छी तरह से काम करता है:
start :: (() -> r) -> r
start f = f()
end :: (() :> a) -> a
end (() :> a) = a
stack x f = f x
runF s = s end
_1 = liftS0 1
neg = liftS1 negate
add = liftS2 (+)
-- aka "push"
liftS0 :: a -> (s :~> (s :> a))
liftS0 a s = stack $ s :> a
liftS1 :: (a -> b) -> ((s :> a) :~> (s :> b))
liftS1 f (s :> a) = stack $ s :> f a
liftS2 :: (a -> b -> c) -> ((s :> a :> b) :~> (s :> c))
liftS2 f (s :> a :> b) = stack $ s :> f a b
सरल कार्यों तुच्छता से उनकी संगत ढेर परिवर्तनों में तब्दील किया जा सकता है। कुछ खेल के चारों ओर सुखद परिणाम प्राप्त होते हैं अब तक:
ghci> runF $ start _1 _1 neg add
0
मुसीबत आता है जब मैं उच्च क्रम कार्यों के साथ इस विस्तार करने के लिए प्रयास करें।
-- this requires ImpredicativeTypes...not really sure what that means
-- also this implementation seems way too simple to be correct
-- though it does typecheck. I arrived at this after pouring over types
-- and finally eta-reducing the (s' -> r) function argument out of the equation
-- call (a :> f) h = f a h
call :: (s :> (s :~> s')) :~> s'
call (a :> f) = f a
call
, प्रपत्र s
के रूप (s :> (s :~> s'))
के ढेर को बदलने के लिए अनिवार्य रूप से द्वारा इसके बारे में "आराम" करने के लिए "लागू करने के" परिवर्तन (ढेर की नोक पर आयोजित) माना जाता है। मुझे लगता है यह चाहिए काम इस तरह:
ghci> runF $ start _1 (liftS0 neg) call
-1
लेकिन वास्तविकता में, यह मेरे एक विशाल प्रकार मेल नहीं खाता त्रुटि देता है। मैं क्या गलत कर रहा हूं? क्या "ढेर परिवर्तन" प्रतिनिधित्व पर्याप्त रूप से उच्च-आदेश कार्यों को संभाल सकता है, या क्या मुझे इसे समायोजित करने की आवश्यकता है?
एनबी। start push 1 push 2 add end
के बजाय, इन लोगों ने इसे कैसे किया, इसके विपरीत, मैं इसे runF $ start (push 1) (push 2) add
होना चाहता हूं, यह विचार यह है कि शायद बाद में मैं कुछ टाइपक्लास जादू का काम कर सकता हूं ताकि push
कुछ अक्षरों के लिए अंतर्निहित हो सके।
- https://github.com/leonidas/codeblog/blob/master/2012/2012-02-17-concatenative-haskell.md
- https://gist.github.com/1847747
वास्तव में, मैं 'start' का भी छुटकारा पाने के लिए चाहते हैं, और सिर्फ' runF $ _1 _1 add' है, हालांकि मैं वास्तव में नहीं दिख रहा है कि इस सेटअप के साथ संभव है । –
जटिल प्रकार रैंक-एन प्रकारों का एक सामान्यीकरण हैं, जो कि किसी भी प्रकार के कन्स्ट्रक्टर के अंदर एक फॉरल की अनुमति देता है, न केवल कार्य प्रकार। – Carl