diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,12 @@
 
 `pandoc-lua-marshal` uses [PVP Versioning][].
 
+## 0.2.2
+
+Released 2023-03-15.
+
+-   Add `__tostring` metamethods to *Blocks* and *Inlines*.
+
 ## 0.2.1.1
 
 Released 2023-03-13.
diff --git a/pandoc-lua-marshal.cabal b/pandoc-lua-marshal.cabal
--- a/pandoc-lua-marshal.cabal
+++ b/pandoc-lua-marshal.cabal
@@ -1,6 +1,6 @@
 cabal-version:       2.4
 name:                pandoc-lua-marshal
-version:             0.2.1.1
+version:             0.2.2
 synopsis:            Use pandoc types in Lua
 description:         This package provides functions to marshal and unmarshal
                      pandoc document types to and from Lua.
diff --git a/src/Text/Pandoc/Lua/Marshal/Block.hs b/src/Text/Pandoc/Lua/Marshal/Block.hs
--- a/src/Text/Pandoc/Lua/Marshal/Block.hs
+++ b/src/Text/Pandoc/Lua/Marshal/Block.hs
@@ -86,6 +86,13 @@
       =#> functionResult pushBlocks "Blocks" "modified list"
     rawset (nth 3)
 
+    pushName "__tostring"
+    pushDocumentedFunction $ lambda
+      ### liftPure show
+      <#> parameter peekBlocksFuzzy "Blocks" "self" ""
+      =#> functionResult pushString "string" "native Haskell representation"
+    rawset (nth 3)
+
     pushName "__tojson"
     pushDocumentedFunction $ lambda
       ### liftPure encode
diff --git a/src/Text/Pandoc/Lua/Marshal/Inline.hs b/src/Text/Pandoc/Lua/Marshal/Inline.hs
--- a/src/Text/Pandoc/Lua/Marshal/Inline.hs
+++ b/src/Text/Pandoc/Lua/Marshal/Inline.hs
@@ -79,6 +79,13 @@
       =#> functionResult pushInlines "Blocks" "modified list"
     rawset (nth 3)
 
+    pushName "__tostring"
+    pushDocumentedFunction $ lambda
+      ### liftPure show
+      <#> parameter peekInlinesFuzzy "Inlines" "self" ""
+      =#> functionResult pushString "string" "native Haskell representation"
+    rawset (nth 3)
+
     pushName "__tojson"
     pushDocumentedFunction $ lambda
       ### liftPure encode
diff --git a/test/test-block.lua b/test/test-block.lua
--- a/test/test-block.lua
+++ b/test/test-block.lua
@@ -409,6 +409,17 @@
         )
       end)
     },
+    group 'tostring' {
+      test('works on an empty list', function ()
+        assert.are_equal(tostring(Blocks{}), '[]')
+      end),
+      test('para singleton', function ()
+        assert.are_equal(
+          tostring(Blocks{Para 'Hallo'}),
+          '[Para [Str "Hallo"]]'
+        )
+      end),
+    },
     group 'walk' {
       test('modifies Inline subelements', function ()
         local blocks = Blocks{Para 'Hello, World!'}
diff --git a/test/test-inline.lua b/test/test-inline.lua
--- a/test/test-inline.lua
+++ b/test/test-inline.lua
@@ -325,6 +325,20 @@
         )
       end)
     },
+    group 'tostring' {
+      test('works on an empty list', function ()
+        assert.are_equal(
+          tostring(Inlines{}),
+          '[]'
+        )
+      end),
+      test('simple inlines', function ()
+        assert.are_equal(
+          tostring(Inlines 'Bonjour, Monsieur !'),
+          '[Str "Bonjour,",Space,Str "Monsieur",Space,Str "!"]'
+        )
+      end),
+    },
     group 'walk' {
       test('modifies Inline subelements', function ()
         assert.are_same(
