क्या आधुनिक जीएचसी संस्करणों में किसी भी प्रकार का प्रमाण मिटाना है?


22

मान लीजिए कि मेरे पास एक पैरामीटर है जो केवल प्रकार प्रणाली के लाभ के लिए मौजूद है, उदाहरण के लिए इस छोटे से कार्यक्रम में:

{-# LANGUAGE GADTs #-}
module Main where
import Data.Proxy
import Data.List

data MyPoly where
  MyConstr :: Proxy a -> a -> (Proxy a -> a -> Int -> Int) -> MyPoly

listOfPolys :: [MyPoly]
listOfPolys = [MyConstr Proxy 5 (const (+))
              , MyConstr Proxy 10 (const (+))
              , MyConstr Proxy 15 (const (+))]

main = print $ foldl' (\v (MyConstr p n a) -> a p n v) 0 listOfPolys

संरचना में प्रॉक्सी तर्कों और सदस्यों को वास्तव में कंपाइल समय पर मौजूद रहने की जरूरत है ताकि पॉलीमॉर्फिक मायपॉली को बनाए रखते हुए टाइप चेकिंग में मदद मिल सके (इस मामले में, कार्यक्रम इसके बिना संकलन करेगा, लेकिन यह आकस्मिक उदाहरण एक अधिक सामान्य समस्या है जहां हैं सबूत या परदे के पीछे जो केवल संकलन के समय की आवश्यकता होती है) - प्रॉक्सी के लिए केवल एक कंस्ट्रक्टर है, और प्रकार तर्क एक प्रेत प्रकार है।

Ghc के साथ संकलित करने से -ddump-stgपता चलता है कि कम से कम STG चरण में, निर्माता के लिए प्रॉक्सी तर्क का कोई क्षरण नहीं है या निर्माणकर्ता के लिए तीसरा तर्क नहीं है।

क्या इन्हें केवल संकलन-समय के रूप में चिह्नित करने का कोई तरीका है, या अन्यथा सबूत मिटाने और उन्हें बाहर करने में ghc की मदद करें?

जवाबों:


20

दरअसल, आपका कोड Proxyकंस्ट्रक्टर में संग्रहीत होने के लिए ले जाता है:

ProxyOpt.listOfPolys8 :: ProxyOpt.MyPoly
[GblId, Caf=NoCafRefs, Unf=OtherCon []] =
    CCS_DONT_CARE ProxyOpt.MyConstr! [Data.Proxy.Proxy
                                      ProxyOpt.listOfPolys9
                                      ProxyOpt.listOfPolys4];

हालांकि, एक छोटे से बदलाव के साथ, हमें वांछित अनुकूलन प्राप्त होता है। और नहीं Proxy!

ProxyOpt.listOfPolys8 :: ProxyOpt.MyPoly
[GblId, Caf=NoCafRefs, Unf=OtherCon []] =
    CCS_DONT_CARE ProxyOpt.MyConstr! [ProxyOpt.listOfPolys9
                                      ProxyOpt.listOfPolys4];

मैंने क्या किया? मैंने Proxyक्षेत्र को सख्त बनाया :

data MyPoly where
  MyConstr :: !(Proxy a) -> a -> (Proxy a -> a -> Int -> Int) -> MyPoly
           -- ^ --

सामान्य तौर पर, हम बोतलों के कारण गैर-सख्त परदे नहीं मिटा सकते हैं। Proxyऔर undefinedदोनों प्रकार के हैं, Proxy aलेकिन वे अवलोकन के समकक्ष नहीं हैं, इसलिए हमें उन्हें रनटाइम में अंतर करना होगा।

इसके बजाय, एक सख्त के पास Proxyकेवल एक मूल्य है, इसलिए जीएचसी इसे दूर कर सकता है।

यद्यपि (गैर-कंस्ट्रक्टर) फ़ंक्शन पैरामीटर को ऑप्टिमाइज़ करने के लिए कोई समान सुविधा नहीं है, हालांकि। आपके क्षेत्र (Proxy a -> a -> Int -> Int)को एक Proxyरनटाइम की आवश्यकता होगी ।


15

आप जो चाहते हैं उसे पूरा करने के दो तरीके हैं।

थोड़ा पुराना तरीका GHC.Prim से प्रॉक्सी # का उपयोग करना है, जिसे संकलन-समय पर मिटाने की गारंटी है।

{-# LANGUAGE GADTs, MagicHash #-}
module Main where

import Data.List
import GHC.Prim

data MyPoly where
  MyConstr :: Proxy# a -> a -> (Proxy# a -> a -> Int -> Int) -> MyPoly

listOfPolys :: [MyPoly]
listOfPolys = [MyConstr proxy# 5 (\_ -> (+))
              , MyConstr proxy# 10 (\_ -> (+))
              , MyConstr proxy# 15 (\_ -> (+))]

हालांकि यह थोड़ा बोझिल है।

दूसरा तरीका यह है कि Proxyकुल मिलाकर:

{-# LANGUAGE GADTs #-}

module Main where

import Data.List

data MyPoly where
  MyConstr :: a -> (a -> Int -> Int) -> MyPoly

listOfPolys :: [MyPoly]
listOfPolys = [ MyConstr 5  (+)
              , MyConstr 10 (+)
              , MyConstr 15 (+)
              ]

main = print $ foldl' (\v (MyConstr n a) -> a n v) 0 listOfPolys

आजकल, हमारे पास कुछ ऐसे उपकरण हैं, जिनके बिना काम करना आसान हो जाता है Proxy: उदाहरण के लिए, AllowAmbiguousTypesऔर TypeApplications, उदाहरण के लिए, इसका मतलब है कि आप जिस प्रकार का मतलब है, उसे सीधे लागू कर सकते हैं। मुझे नहीं पता कि आपका उपयोग-मामला क्या है, लेकिन इसे ले लीजिए (उदाहरण के लिए):

import Data.Proxy

asTypeP :: a -> Proxy a -> a
asTypeP x _ = x

readShow :: (Read a, Show a) => Proxy a -> String -> String
readShow p x = show (read x `asTypeP` p)

>>> readShow (Proxy :: Proxy Int) "01"
"1"

हम पढ़ना चाहते हैं और फिर कुछ प्रकार का मान दिखाते हैं, इसलिए हमें यह संकेत करने का तरीका चाहिए कि वास्तविक प्रकार क्या है। यहां बताया गया है कि आप इसे एक्सटेंशन के साथ कैसे करेंगे:

{-# LANGUAGE AllowAmbiguousTypes, TypeApplications, ScopedTypeVariables #-}

readShow :: forall a. (Read a, Show a) => String -> String
readShow x = show (read x :: a)

>>> readShow @Int "01"
"1"

मेरी राय में अंतिम विकल्प (कोई भी समीपता) सबसे अच्छा नहीं है।
ची
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.