Быстрые указатели-указатели (статические, распаковывающиеся и т.д.) С библиотекой Struct

Я заинтересован в использовании более эффективных указателей для проекта, реализующего императивный язык в Haskell. Для этого уже существует библиотека: Struct. На нем есть сообщение в блоге и краткая документация.

Проблема заключается только в довольно сложном примере ссылок на деревья. Для кого-то вроде меня, который не использует Haskell на ежедневной основе, довольно утомительно сражаться с небольшим документированным кодом, шаблоном haskell и т.д.

Мне понадобится более простой пример для начала, по выражению одного из двух типов данных:

import Data.IORef

data DLL a = DLL a (Maybe (IORef (DLL a))) (Maybe (IORef (DLL a)))

data DLLINT = DLLINT Int (Maybe (IORef DLLINT)) (Maybe (IORef DLLINT))

Это должно быть всего лишь несколько простых строк для тех, кто свободно говорит в Haskell/GHC.

Как я могу выразить один из вышеперечисленных типов данных с помощью библиотеки Struct?

Ответ 1

Мне удалось получить тип DLL, работающий с Structs следующим образом:

{-# LANGUAGE TemplateHaskell, RoleAnnotations #-}
module DubLiList where

import Control.Monad.Primitive
import Data.Struct.TH
import Data.Struct
import Data.Struct.Internal


makeStruct [d|
  data DLL a s = DLL
    { prev :: !(DLL a s)
    , value :: a
    , next :: !(DLL a s)
    }
  |]

new :: (PrimMonad m) => a -> m (DLL a (PrimState m))
new x = st $ newDLL Nil x Nil

insert :: (PrimMonad m) => a -> DLL a (PrimState m) -> m (DLL a (PrimState m))
insert x this = st $ do
    prev' <- get prev this
    new <- newDLL prev' x this
    set prev this new
    set next prev' new
    return new

delete :: (PrimMonad m) => DLL a (PrimState m) -> m ()
delete this = st $ do
    prev' <- get prev this
    next' <- get next this
    set next prev' next'
    set prev next' prev'

toList :: (PrimMonad m) => DLL a (PrimState m) -> m [a]
toList this = st $ do
    if isNil this then return [] else do
        x <- getField value this
        that <- get next this
        (x:) <$> toList that

Вот пример его использования:

main :: IO ()
main = do
    dll <- new "foo"           -- [foo]
    dll' <- insert "bar" dll   -- [bar, foo]
    insert "baz" dll           -- [bar, baz, foo]

    xs <- toList dll'
    print xs