簡體   English   中英

在Haskell中建模異構圖

[英]Modeling heterogenous graphs in Haskell

如何在haskell中對我稱之為“異構圖”的模型進行建模,以便在編譯時驗證圖的類型正確性?

為此,異構圖是一組節點,每個節點具有特定類型標簽和一組邊,每個邊具有源類型標簽和目標類型標簽。

我們希望靜態地確保在將邊添加到圖中時,該邊的源類型標簽與源節點的類型標簽匹配,並且該邊的目標類型標簽與目標節點的類型標簽匹配。 但是我們不希望以微不足道的方式做到這一點(通過強制整個圖形僅包含具有一個特定類型標簽的節點)。

我不確定如何在編譯時強制執行此操作 - 我認為它要求您的圖形完全是靜態的? - 但是在運行時使用Typeable強制執行它是相對簡單的。 這是一個看起來像什么的草圖。 首先,我將從類型化的NodeEdge類型開始:

data Node a = Node a
data Edge a b = Edge !Int !Int

將它們包裹在存在物中:

{-# LANGUAGE ExistentialQuantification #-}

import Data.Typeable

data SomeNode
  = forall a. (Typeable a)
  => SomeNode (Node a)

data SomeEdge
  = forall a b. (Typeable a, Typeable b)
  => SomeEdge (Edge a b)

擁有使用存在量化類型的異構圖數據類型:

import Data.IntMap (IntMap)

-- Not a great representation, but simple for illustration.
data Graph = Graph !(IntMap SomeNode) [SomeEdge]

然后執行動態類型檢查的操作:

{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}

import qualified Data.IntMap as IntMap

addNode
  :: forall a. (Typeable a)
  => Int -> a -> Graph -> Maybe Graph
addNode i x (Graph ns es) = case IntMap.lookup i ns of

  -- If a node already exists at a given index:
  Just (SomeNode (existing :: Node e)) -> case eqT @e @a of

    -- Type-preserving replacement is allowed, but…
    Just Refl -> Just $ Graph ns' es

    -- …*type-changing* replacement is *not* allowed,
    -- since it could invalidate existing edges.
    Nothing -> Nothing

  -- Insertion is of course allowed.
  Nothing -> Just $ Graph ns' es

  where
    ns' = IntMap.insert i (SomeNode (Node x)) ns

-- To add an edge:
addEdge
  :: forall a b. (Typeable a, Typeable b)
  => Edge a b -> Graph -> Maybe Graph
addEdge e@(Edge f t) (Graph ns es) = do

  -- The ‘from’ node must exist…
  SomeNode (fn :: Node tfn) <- IntMap.lookup f ns
  -- …and have the correct type; and
  Refl <- eqT @a @tfn

  -- The ‘to’ node must exist…
  SomeNode (tn :: Node ttn) <- IntMap.lookup t ns
  -- …and have the correct type.
  Refl <- eqT @b @ttn

  pure $ Graph ns $ SomeEdge e : es

現在這成功了:

pure (Graph mempty mempty)
  >>= addNode 0 (1 :: Int)
  >>= addNode 1 ('x' :: Char)
  >>= addEdge (Edge 0 1 :: Edge Int Char)

但改變Int / CharEdge Int Char無效類型,或0 / 1無效的指數,將失敗並返回Nothing

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM