-
StaticPointers -
- Since:
-
7.10.1
Разрешает использование синтаксиса статических указателей.
Расширение языка StaticPointers добавляет новый синтаксический элемент static e, который представляет собой ссылку на закрытое выражение ⟨e⟩. Эта ссылка стабильна и портативна, поскольку она остается действительной в разных процессах на, возможно, разных машинах. Таким образом, процесс может создать ссылку и передать ее другому процессу, который может разрешить ее до ⟨e⟩.
При включенном этом расширении, static больше не является допустимым идентификатором.
Статические указатели были впервые предложены в статье Towards Haskell in the cloud, Джеффа Эпштейна, Эндрю П. Блэка и Саймона Пейтона-Джонса, в трудах 4-й конференции ACM по языку Haskell, стр. 118-129, ACM, 2011.
6.15.3.1. Использование статических указателей
Каждой ссылке присваивается ключ, который может быть использован для поиска ее во время выполнения с помощью GHC.StaticPtr.unsafeLookupStaticPtr, который использует глобальную и неизменяемую таблицу, называемую таблицей статических указателей. Компилятор включает записи в эту таблицу для всех статических форм, найденных в связанных модулях. Значение может быть получено из ссылки с помощью GHC.StaticPtr.deRefStaticPtr.
Тело e выражения static e должно быть закрытым выражением. Выражение считается *закрытым*, если все его свободные (типовые) переменные являются закрытыми. Переменная считается *закрытой*, если она связана с помощью let-связи с *закрытым* выражением и ее тип является *закрытым*. Тип считается *закрытым*, если он не содержит свободных переменных.
Все следующие примеры допустимы:
inc :: Int -> Int inc x = x + 1 ref1 = static 'a' ref2 = static inc ref3 = static (inc 1) ref4 = static ((\x -> x + 1) (1 :: Int)) ref5 = static (let x = 'a' in x) ref6 = let x = 'a' in static x
В то время как следующие определения будут отклонены:
ref7 y = let x = y in static x -- x is not closed
ref8 y = static (let x = 1 in y) -- y is not let-bound
ref9 (y :: a) = let x = undefined :: a
in static x -- x has a non-closed type
Примечание
Модули, загруженные в GHCi с помощью команды :load, могут использовать StaticPointers и static выражения, но вводимые в интерактивную оболочку REPL - нет. Это ограничение GHCi; подробнее см. #12356.
Примечание
Множество ключей, используемых для поиска статических указателей в таблице статических указателей, не гарантируется стабильным для разных двоичных файлов программы. Другими словами, гарантируется, что только процессы, запущенные из одного и того же двоичного файла программы, будут использовать одно и то же множество ключей.
6.15.3.2. Статическая семантика статических указателей
Неформально, если у нас есть закрытое выражение
e :: forall a_1 ... a_n . t
то статическая форма имеет тип
static e :: (IsStatic p, Typeable a_1, ... , Typeable a_n) => p t
Статическая форма определяет значение типа StaticPtr t, но, подобно OverloadedLists и OverloadedStrings, это литеральное выражение перегружено, чтобы позволить поднять StaticPtr в другой тип неявно через класс IsStatic:
class IsStatic p where
fromStaticPtr :: Typeable a => StaticPtr a -> p a
Единственный предопределённый экземпляр — очевидный, который ничего не делает:
instance IsStatic StaticPtr where
fromStaticPtr sptr = sptr
Кроме того, тип t должен иметь экземпляр класса Typeable. Следующие примеры поэтому некорректны:
static id -- No Typeable instance for (a -> a) static Control.Monad.ST.runST -- No Typeable instance for ((forall s. ST s a) -> a)
Однако, при использовании соответствующих обёртных типов, вышеперечисленные ограничения не приводят к потере общности:
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE ExistentialQuantification #-}
{-# LANGUAGE Rank2Types #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE StaticPointers #-}
import Control.Monad.ST
import Data.Typeable
import GHC.StaticPtr
data Dict c = c => Dict
g1 :: Typeable a => StaticPtr (Dict (Show a) -> a -> String)
g1 = static (\Dict -> show)
data Rank2Wrapper f = R2W (forall s. f s)
deriving Typeable
newtype Flip f a s = Flip { unFlip :: f s a }
deriving Typeable
g2 :: Typeable a => StaticPtr (Rank2Wrapper (Flip ST a) -> a)
g2 = static (\(R2W f) -> runST (unFlip f))