Modern GHC versiyonlarında herhangi bir kanıt silme işlemi var mı?


22

Örneğin, bu küçük programda olduğu gibi yalnızca tür sisteminin faydası için var olan bir parametreniz olduğunu varsayalım:

{-# 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

Proxy argümanları ve yapıdaki üyelerin, polimorfik MyPoly'yi korurken tip kontrolüne yardımcı olmak için sadece derleme zamanında var olmaları gerekir (bu durumda, program onsuz derlenecektir, ancak bu çelişkili örnek, daha genel bir problemdir. yalnızca derleme zamanında gerekli olan provalar veya proxy'ler) - Proxy için yalnızca bir kurucu vardır ve tür argümanı hayali bir türdür.

Ghc ile derleme -ddump-stg, en azından STG aşamasında, kurucuya Proxy argümanının veya kurucuya üçüncü argümanın silinmediğini gösterir.

Bunları yalnızca derleme zamanı olarak işaretlemenin ya da ghc'ye kanıt silme ve hariç tutma konusunda yardımcı olmanın herhangi bir yolu var mı?

Yanıtlar:


20

Aslında, kodunuz Proxyyapıcıda depolanmasına neden olur :

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

Ancak, küçük bir değişiklikle, istenen optimizasyonu elde ederiz. Artık yok Proxy!

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

Ne yaptım? Yaptığım Proxysaha sıkı :

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

Genel olarak, dipleri nedeniyle katı olmayan proxy'leri silemeyiz. Proxyve undefinedher ikisi de türdür Proxy aancak gözlemsel olarak eşdeğer değildir, bu yüzden bunları çalışma zamanında ayırt etmeliyiz.

Bunun yerine, bir katı Proxysadece bir değere sahiptir, bu nedenle GHC bunu optimize edebilir.

Yine de (yapıcı olmayan) işlev parametresini optimize etmek için benzer bir özellik yoktur. Kişisel alan (Proxy a -> a -> Int -> Int)bir gerektirecektir Proxyzamanında.


15

İstediğinizi başarmanın iki yolu vardır.

Biraz daha eski yol, derleme zamanında silineceği garanti edilen GHC.Prim'den Proxy # kullanmaktır .

{-# 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 (\_ -> (+))]

Her ne kadar bu biraz hantal.

Diğer yol ise Proxytamamen vazgeçmektir :

{-# 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

Günümüzde, olmadan çalışmayı kolaylaştıran bazı araçlarımız var Proxy: AllowAmbiguousTypesve gibi uzantılar TypeApplications, demek istediğiniz türü doğrudan uygulayabileceğiniz anlamına gelir. Kullanım durumunuzun ne olduğunu bilmiyorum, ancak bu (tutarlı) örneği alın:

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"

Bir tür değeri okumak ve sonra göstermek istiyoruz, bu yüzden gerçek türün ne olduğunu belirtmek için bir yola ihtiyacımız var. Uzantılarla nasıl yapacağınız aşağıda açıklanmıştır:

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

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

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

Bence son seçenek (proxy yok) en iyisi.
chi
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.