รุ่น GHC ที่ทันสมัยมีการลบหลักฐานชนิดใดบ้าง


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

อาร์กิวเมนต์ Proxy และสมาชิกในโครงสร้างจำเป็นต้องมีอยู่จริงในเวลาคอมไพล์เพื่อช่วยในการตรวจสอบชนิดในขณะที่รักษา polymorphic MyPoly (ในกรณีนี้โปรแกรมจะคอมไพล์โดยไม่มีมัน แต่ตัวอย่างที่ถูกประดิษฐ์นี้เป็นปัญหาทั่วไปที่มี หลักฐานหรือพร็อกซี่ที่จำเป็นต้องใช้ในเวลารวบรวมเท่านั้น) - มีคอนสตรัคเตอร์เดียวเท่านั้นสำหรับพร็อกซีและอาร์กิวเมนต์ประเภทคือประเภทผี

รวบรวมด้วย 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มีเพียงค่าเดียวดังนั้น GHC จึงสามารถปรับค่านั้นให้เหมาะสม

ไม่มีคุณสมบัติที่คล้ายกันในการปรับพารามิเตอร์ฟังก์ชัน (ที่ไม่ใช่ตัวสร้าง) ให้เหมาะสม เขตข้อมูลของคุณ(Proxy a -> a -> Int -> Int)จะต้องมีProxyที่รันไทม์


15

มีสองวิธีในการบรรลุสิ่งที่คุณต้องการ

วิธีที่เก่ากว่าเล็กน้อยคือใช้Proxy #จาก 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"

ทางเลือกสุดท้าย (ไม่มีพร็อกซี่) เป็นทางเลือกที่ดีที่สุดในความคิดของฉัน
Chi
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.