Source code on Github
-------------------------------------------------------------------------------------
-- List notation without having to use `nil/[]`,
-- achieved by implicitly coercing elements to singleton lists.

-- For a more general treatment, where we inject into arbitrary sums/variants
-- at the cost of worse type inference, see Prelude.Variants.
-------------------------------------------------------------------------------------
open import Prelude.Init; open SetAsType

module Prelude.Lists.NoNil where

private
  variable X A B : Type
  pattern ๐•ƒ = injโ‚ refl; pattern โ„ = injโ‚‚ refl

record List? (X A : Type) : Typeโ‚ where
  field isList : (A โ‰ก X) โŠŽ (A โ‰ก List X)
  syntax isList {X}{A} = A isListOf? X

  toL : A โ†’ List X
  toL with isList
  ... | ๐•ƒ = [_]
  ... | โ„ = id
  syntax toL {A = A} = toL[ A ]
open List? โฆƒ...โฆ„ public

instance
  Pick๐•ƒ : List? X X
  Pick๐•ƒ = record {isList = ๐•ƒ}

  Pickโ„ : List? X (List X)
  Pickโ„ = record {isList = โ„}

test-variant : โฆƒ List? X A โฆ„ โ†’ A โ†’ List X
test-variant {X}{A}
  with A isListOf? X
... | ๐•ƒ = [_]
... | โ„ = id

infixr 4 _โŠ•_
_โŠ•_ : โฆƒ List? X A โฆ„ โ†’ โฆƒ List? X B โฆ„ โ†’ A โ†’ B โ†’ List X
x โŠ• y = toL x ++ toL y

open import Prelude.General; open MultiTest
_ = List โ„•
 โˆ‹โ‹ฎ []
  โ‹ฎ [ 0 ]
  โ‹ฎ 0 โŠ• 1
  โ‹ฎ 0 โŠ• [ 1 ]
  โ‹ฎ [ 0 ] โŠ• 1
  โ‹ฎ [ 0 ] โŠ• [ 1 ]
  โ‹ฎ 0 โŠ• 1 โŠ• 2
  โ‹ฎ 0 โŠ• 1 โŠ• [ 2 ]
  โ‹ฎ 0 โŠ• [ 1 ] โŠ• 2
  โ‹ฎ [ 0 ] โŠ• 1 โŠ• 2
  โ‹ฎ 0 โŠ• [ 1 ] โŠ• [ 2 ]
  โ‹ฎ [ 0 ] โŠ• [ 1 ] โŠ• 2
  โ‹ฎ [ 0 ] โŠ• 1 โŠ• [ 2 ]
  โ‹ฎ [ 0 ] โŠ• [ 1 ] โŠ• [ 2 ]
  โ‹ฎโˆ