বৈধ গ্রাফের ধরণটি কি ধলে এনকোড করা যাবে?


10

আমি ধলে একটি উইকি (নির্দেশিত গ্রাফের সমন্বিত নথিগুলির একটি সেট) উপস্থাপন করতে চাই। এই ডকুমেন্টগুলি এইচটিএমএলকে রেন্ডার করা হবে এবং আমি ভাঙা লিঙ্কগুলি কখনও উত্পন্ন হতে আটকাতে চাই। আমি এটি দেখতে পাচ্ছি, এটি টাইপ সিস্টেমের মাধ্যমে অবৈধ গ্রাফগুলি (অস্তিত্বহীন নোডগুলির লিঙ্কযুক্ত গ্রাফ) দ্বারা বা কোনও সম্ভাব্য গ্রাফের ত্রুটির একটি তালিকা ফেরত দেওয়ার জন্য একটি ফাংশন লিখে (যেমন "সম্ভাব্য গ্রাফে এক্স, নোড এ একটি অ-বিদ্যমান নোড বি ") এর লিঙ্ক ধারণ করে।

একটি নিষ্পাপ সংলগ্ন তালিকার উপস্থাপনাটি এর মতো দেখতে পারে:

let Node : Type = {
    id: Text,
    neighbors: List Text
}
let Graph : Type = List Node
let example : Graph = [
    { id = "a", neighbors = ["b"] }
]
in example

এই উদাহরণটি স্পষ্ট করে তোলে যে, এই ধরণের মানগুলি বৈধ গ্রাফগুলির সাথে মিল নয় ("বি" এর আইডির সাথে কোনও নোড নেই, তবে "বি" আইডি সহ নোড রয়েছে "বি" আইডি সহ প্রতিবেশীকে নির্ধারণ করে)। তদুপরি, প্রতিটি নোডের প্রতিবেশীদের ভাঁজ করে এই বিষয়গুলির একটি তালিকা তৈরি করা সম্ভব নয়, কারণ llাল ডিজাইনের মাধ্যমে স্ট্রিং তুলনা সমর্থন করে না।

এমন কোন উপস্থাপনা রয়েছে যা ভাঙা লিঙ্কগুলির তালিকার গণনা বা টাইপ সিস্টেমের মাধ্যমে ভাঙা লিঙ্কগুলি বাদ দেওয়ার জন্য অনুমতি দেয়?

আপডেট: আমি সবেমাত্র আবিষ্কার করেছি যে ন্যাচারালরা Dhaলের সাথে তুলনীয়। সুতরাং আমি অনুমান করি যে কোনও ফাংশন কোনও অবৈধ প্রান্তগুলি ("ভাঙা লিঙ্কগুলি") সনাক্ত করতে এবং যদি সনাক্তকারীরা ন্যাচারাল ছিলেন তবে কোনও সনাক্তকারীর সদৃশ ব্যবহারের জন্য রচনা করা যেতে পারে।

গ্রাফ ধরণের সংজ্ঞা দেওয়া যায় কিনা এর মূল প্রশ্নটি রয়ে গেছে।


পরিবর্তে প্রান্তটি প্রান্তগুলির তালিকা হিসাবে উপস্থাপন করুন। নোডগুলি বিদ্যমান প্রান্তগুলি থেকে অনুমান করা যায়। প্রতিটি প্রান্তে উত্স নোড এবং একটি গন্তব্য নোড থাকবে তবে সংযোগ বিচ্ছিন্ন নোডগুলিকে সমন্বিত করতে গন্তব্যটি beচ্ছিক হতে পারে।
চিপনার

উত্তর:


18

হ্যাঁ, আপনি কোনও ধরণের সুরক্ষিত, পরিচালিত, সম্ভবত-চক্রীয়, গ্রাফের ধালে মডেল করতে পারেন:

let List/map =
      https://prelude.dhall-lang.org/v14.0.0/List/map sha256:dd845ffb4568d40327f2a817eb42d1c6138b929ca758d50bc33112ef3c885680

let Graph
    : Type
    =     forall (Graph : Type)
      ->  forall  ( MakeGraph
                  :     forall (Node : Type)
                    ->  Node
                    ->  (Node -> { id : Text, neighbors : List Node })
                    ->  Graph
                  )
      ->  Graph

let MakeGraph
    :     forall (Node : Type)
      ->  Node
      ->  (Node -> { id : Text, neighbors : List Node })
      ->  Graph
    =     \(Node : Type)
      ->  \(current : Node)
      ->  \(step : Node -> { id : Text, neighbors : List Node })
      ->  \(Graph : Type)
      ->  \ ( MakeGraph
            :     forall (Node : Type)
              ->  Node
              ->  (Node -> { id : Text, neighbors : List Node })
              ->  Graph
            )
      ->  MakeGraph Node current step

let -- Get `Text` label for the current node of a Graph
    id
    : Graph -> Text
    =     \(graph : Graph)
      ->  graph
            Text
            (     \(Node : Type)
              ->  \(current : Node)
              ->  \(step : Node -> { id : Text, neighbors : List Node })
              ->  (step current).id
            )

let -- Get all neighbors of the current node
    neighbors
    : Graph -> List Graph
    =     \(graph : Graph)
      ->  graph
            (List Graph)
            (     \(Node : Type)
              ->  \(current : Node)
              ->  \(step : Node -> { id : Text, neighbors : List Node })
              ->  let neighborNodes
                      : List Node
                      = (step current).neighbors

                  let nodeToGraph
                      : Node -> Graph
                      =     \(node : Node)
                        ->  \(Graph : Type)
                        ->  \ ( MakeGraph
                              :     forall (Node : Type)
                                ->  forall (current : Node)
                                ->  forall  ( step
                                            :     Node
                                              ->  { id : Text
                                                  , neighbors : List Node
                                                  }
                                            )
                                ->  Graph
                              )
                        ->  MakeGraph Node node step

                  in  List/map Node Graph nodeToGraph neighborNodes
            )

let {- Example node type for a graph with three nodes

           For your Wiki, replace this with a type with one alternative per document
        -}
    Node =
      < Node0 | Node1 | Node2 >

let {- Example graph with the following nodes and edges between them:

                       Node0 ↔ Node1
                         ↓
                       Node2
                         ↺

           The starting node is Node0
        -}
    example
    : Graph
    = let step =
                \(node : Node)
            ->  merge
                  { Node0 = { id = "0", neighbors = [ Node.Node1, Node.Node2 ] }
                  , Node1 = { id = "1", neighbors = [ Node.Node0 ] }
                  , Node2 = { id = "2", neighbors = [ Node.Node2 ] }
                  }
                  node

      in  MakeGraph Node Node.Node0 step

in  assert : List/map Graph Text id (neighbors example) === [ "1", "2" ]

এই উপস্থাপনাটি ভাঙ্গা প্রান্তের অনুপস্থিতির গ্যারান্টি দেয়।

আপনি এই উত্তরটি এমন একটি প্যাকেজে পরিণত করেছেন যা আপনি ব্যবহার করতে পারেন:

সম্পাদনা করুন: এখানে প্রাসঙ্গিক সংস্থান এবং অতিরিক্ত ব্যাখ্যা যা যা চলছে তা আলোকিত করতে সহায়তা করতে পারে:

প্রথমে গাছের জন্য নিম্নলিখিত হাস্কেল প্রকার থেকে শুরু করুন :

data Tree a = Node { id :: a, neighbors :: [ Tree a ] }

আপনি এই ধরণের একটি অলস এবং সম্ভাব্য অসীম ডেটা স্ট্রাকচার হিসাবে ভাবতে পারেন যে আপনি কেবল প্রতিবেশীদের দেখা করা চালিয়ে গেলে কী পাবেন represent

এখন, ভান করা যাক যে উপরোক্ত Treeউপস্থাপনাটি আসলে আমাদের হ'লGraph ডেটাটাইপটির নামকরণ করে Graph:

data Graph a = Node { id :: a, neighbors :: [ Graph a ] }

... তবে আমরা যদি এই ধরণেরটি ব্যবহার করতে চাইতাম তবে আমাদের সরাসরি ধলে inাল টাইপের মডেল করার কোনও উপায় নেই কারণ ঝাল ভাষাটি পুনরাবৃত্ত ডেটা কাঠামোর জন্য অন্তর্নির্মিত সমর্থন সরবরাহ করে না। তাই আমরা কি কাজ করতে পারি?

ভাগ্যক্রমে, Dhaাল-এর মতো অ-পুনরাবৃত্ত ভাষায় রিকার্সিভ ডেটা স্ট্রাকচার এবং পুনরাবৃত্ত ফাংশনগুলি এম্বেড করার আসলে উপায় আছে। আসলে, দুটি উপায় আছে!

আমি প্রথম যে জিনিসটি এই কৌশলটির সাথে আমাকে পরিচয় করিয়েছিলাম তা হ'ল ওয়েডলারের নিম্নলিখিত খসড়া পোস্ট:

... তবে আমি নিম্নলিখিত দুটি হাস্কেল প্রকারটি ব্যবহার করে মূল ধারণাটি সংক্ষেপ করতে পারি:

{-# LANGUAGE RankNTypes #-}

-- LFix is short for "Least fixed point"
newtype LFix f = LFix (forall x . (f x -> x) -> x)

... এবং:

{-# LANGUAGE ExistentialQuantification #-}

-- GFix is short for "Greatest fixed point"
data GFix f = forall x . GFix x (x -> f x)

যে ভাবে LFixএবং GFixকাজ যে আপনি তাদের আপনার পছন্দসই রিকার্সিভ এর "একটি স্তর" বা "corecursive" টাইপ দিতে পারে (অর্থাতf ) এবং তারা তারপর আপনি পুনরাবৃত্তির বা corecursion ভাষা সমর্থন ছাড়াই কিছু যে আকাঙ্ক্ষিত টাইপ শক্তিশালী হিসাবে দিতে ।

উদাহরণ হিসাবে তালিকা ব্যবহার করা যাক। আমরা নিম্নলিখিত ListFধরণের ব্যবহার করে একটি তালিকার "একটি স্তর" মডেল করতে পারি :

-- `ListF` is short for "List functor"
data ListF a next = Nil | Cons a next

সেই সংজ্ঞাটির তুলনা করুন কীভাবে আমরা OrdinaryListএকটি সাধারণ পুনরাবৃত্ত ডেটাটাইপ সংজ্ঞা ব্যবহার করে সাধারণত একটি সংজ্ঞা দেই :

data OrdinaryList a = Nil | Cons a (OrdinaryList a)

মূল পার্থক্যটি হ'ল ListFএকটি অতিরিক্ত ধরণের প্যারামিটার লাগে (next ), যা আমরা সমস্ত পুনরাবৃত্ত / কর্সারসিভ ঘটনার জন্য স্থানধারক হিসাবে ব্যবহার করি।

এখন, সজ্জিত ListF, আমরা এরকম পুনরাবৃত্ত এবং কর্সারসিভ তালিকা সংজ্ঞায়িত করতে পারি:

type List a = LFix (ListF a)

type CoList a = GFix (ListF a)

... কোথায়:

  • List পুনরাবৃত্তির জন্য ভাষা সমর্থন ছাড়াই কার্যকর করা একটি পুনরাবৃত্তির তালিকা
  • CoList কোরকর্সনের জন্য ভাষা সমর্থন ছাড়াই কার্যকর একটি কর্সারসিভ তালিকা

এই উভয় প্রকারের সমতুল্য ("isomorphic to") []যার অর্থ:

  • আপনি reversibly আগে পিছে রূপান্তর করতে পারেন মধ্যে Listএবং[]
  • আপনি reversibly আগে পিছে রূপান্তর করতে পারেন মধ্যে CoListএবং[]

আসুন প্রমাণ করুন যে এই রূপান্তর ফাংশনগুলি সংজ্ঞায়িত করে!

fromList :: List a -> [a]
fromList (LFix f) = f adapt
  where
    adapt (Cons a next) = a : next
    adapt  Nil          = []

toList :: [a] -> List a
toList xs = LFix (\k -> foldr (\a x -> k (Cons a x)) (k Nil) xs)

fromCoList :: CoList a -> [a]
fromCoList (GFix start step) = loop start
  where
    loop state = case step state of
        Nil           -> []
        Cons a state' -> a : loop state'

toCoList :: [a] -> CoList a
toCoList xs = GFix xs step
  where
    step      []  = Nil
    step (y : ys) = Cons y ys

সুতরাং llাল ধরণের প্রয়োগের প্রথম পদক্ষেপটি ছিল পুনরাবৃত্তির Graphধরণের রূপান্তর করা :

data Graph a = Node { id :: a, neighbors :: [ Graph a ] }

... সমতুল্য সহ-পুনরাবৃত্ত উপস্থাপনা:

data GraphF a next = Node { id ::: a, neighbors :: [ next ] }

data GFix f = forall x . GFix x (x -> f x)

type Graph a = GFix (GraphF a)

... যদিও প্রকারগুলি সামান্য সরল করার জন্য আমি এটি GFixক্ষেত্রে বিশেষত করা আরও সহজ যেখানে f = GraphF:

data GraphF a next = Node { id ::: a, neighbors :: [ next ] }

data Graph a = forall x . Graph x (x -> GraphF a x)

হাসেলের কাছে ধালের মতো বেনামে রেকর্ড নেই, তবে তা যদি হয় তবে আমরা সংজ্ঞাটি সংজ্ঞায়িত করে প্রকারটি আরও সহজ করতে পারি GraphF:

data Graph a = forall x . MakeGraph x (x -> { id :: a, neighbors :: [ x ] })

এটি এখন একটি ঝাল ধরণের মতো দেখতে শুরু করছে Graph, বিশেষত আমরা যদি এর xসাথে প্রতিস্থাপন করি node:

data Graph a = forall node . MakeGraph node (node -> { id :: a, neighbors :: [ node ] })

যাইহোক, এখনও একটি শেষ কৌশলযুক্ত অংশ রয়েছে, যা কীভাবে ExistentialQuantificationহাস্কেল থেকে ধলে অনুবাদ করবেন । দেখা যাচ্ছে যে আপনি সর্বদা অস্তিত্বের পরিমাণকে সর্বজনীন মাপদণ্ডে (যেমন forall) নীচের সমতুল্যতা ব্যবহার করে অনুবাদ করতে পারেন :

exists y . f y ≅ forall x . (forall y . f y -> x) -> x

আমি বিশ্বাস করি এটিকে "স্কোলাইমাইজেশন" বলা হয়

আরও তথ্যের জন্য, দেখুন:

... এবং সেই চূড়ান্ত কৌশলটি আপনাকে ধল ধরণের দেয়:

let Graph
    : Type
    =     forall (Graph : Type)
      ->  forall  ( MakeGraph
                  :     forall (Node : Type)
                    ->  Node
                    ->  (Node -> { id : Text, neighbors : List Node })
                    ->  Graph
                  )
      ->  Graph

... যেখানে forall (Graph : Type)হিসাবে একই ভূমিকা পালন করে forall xপূর্ববর্তী সূত্র এবং forall (Node : Type)হিসাবে একই ভূমিকা পালন করে forall yপূর্ববর্তী সূত্রে।


1
এই উত্তরের জন্য আপনাকে এবং ধলকে বিকাশের জন্য প্রয়োজনীয় সমস্ত পরিশ্রমের জন্য অনেক ধন্যবাদ! আপনি কি এখানে ঝাল / সিস্টেম এফের জন্য কোনও উপাদান আগতকে আরও ভালভাবে বুঝতে পারেন যে আপনি এখানে কী করেছেন, অন্য কোন সম্ভাব্য গ্রাফের উপস্থাপনা কী থাকতে পারে তা আরও ভালভাবে বুঝতে পারে? আমি এখানে একটি ফাংশন লিখতে আপনি যা করেছেন তা প্রসারিত করতে সক্ষম হতে চাই যা গভীরতা প্রথম অনুসন্ধানের মাধ্যমে আপনার গ্রাফ প্রকারের কোনও মান থেকে সংলগ্ন তালিকার উপস্থাপনা তৈরি করতে পারে।
বিজার্ন ওয়েস্টারগার্ড

4
@ জাজার্ন ওয়েস্টারগার্ড: আপনাকে স্বাগতম! দরকারী রেফারেন্স সহ এর পিছনের তত্ত্বটি ব্যাখ্যা করতে আমি আমার উত্তর সম্পাদনা করেছি
গ্যাব্রিয়েল গঞ্জালেজ
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.