Skip to content

Commit 618c714

Browse files
authored
[ close #1384 ] built-in Snoc-lists [< 1, 2, 3 ] (#1383)
1 parent 823230b commit 618c714

File tree

26 files changed

+382
-20
lines changed

26 files changed

+382
-20
lines changed

CHANGELOG.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@ Library changes:
1111
command line options, to `contrib`.
1212
* Monad transformers in `Control.Monad` where restructured
1313
and several new transformer types where added.
14-
* `Data.Colist` and `Data.Colist1` where added to `base`.
14+
* `Data.Colist` and `Data.Colist1` were added to `base`.
15+
* Add `Data.SnocList` to base and `data SnocList` to `Prelude.Types`.
1516
* `Data.Bits`, an interface for bitwise operations, was added to `base`.
1617
* Interfaces `Bifoldable` and `Bitraversable` were added to the `prelude`.
1718
* Interface `Data.Contravariant` for contravariant functors was added
@@ -29,6 +30,8 @@ Syntax changes:
2930
implicit parameters and give multiplicities for parameters. The old syntax
3031
is still available for compatibility purposes but will be removed in the
3132
future.
33+
* Add support for SnocList syntax: `[< 1, 2, 3]` desugars into `Lin :< 1 :< 2 :< 3`
34+
and their semantic highlighting.
3235

3336
Compiler changes:
3437

docs/source/tutorial/typesfuns.rst

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -737,13 +737,26 @@ Note that the constructor names are the same for each — constructor
737737
names (in fact, names in general) can be overloaded, provided that
738738
they are declared in different namespaces (see Section
739739
:ref:`sect-namespaces`), and will typically be resolved according to
740-
their type. As syntactic sugar, any type with the constructor names
740+
their type. As syntactic sugar, any implementation of the names
741741
``Nil`` and ``::`` can be written in list form. For example:
742742

743743
- ``[]`` means ``Nil``
744744

745745
- ``[1,2,3]`` means ``1 :: 2 :: 3 :: Nil``
746746

747+
Similarly, any implementation of the names ``Lin`` and ``:<`` can be
748+
written in **snoc**-list form:
749+
750+
- ``[<]`` mean ``Lin``
751+
- ``[< 1, 2, 3]`` means ``Lin :< 1 :< 2 :< 3``.
752+
753+
and the prelude includes a pre-defined datatype for snoc-lists:
754+
755+
.. code-block:: idris
756+
757+
data SnocList a = Lin | (:<) (SnocList a) a
758+
759+
747760
The library also defines a number of functions for manipulating these
748761
types. ``map`` is overloaded both for ``List`` and ``Vect`` (we'll see more
749762
details of precisely how later when we cover interfaces in

libs/base/Data/SnocList.idr

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
||| A Reversed List
2+
module Data.SnocList
3+
4+
import Decidable.Equality
5+
import Data.List
6+
7+
%default total
8+
9+
infixl 7 <><
10+
infixr 6 <>>
11+
12+
||| 'fish': Action of lists on snoc-lists
13+
public export
14+
(<><) : SnocList a -> List a -> SnocList a
15+
sx <>< [] = sx
16+
sx <>< (x :: xs) = sx :< x <>< xs
17+
18+
||| 'chips': Action of snoc-lists on lists
19+
public export
20+
(<>>) : SnocList a -> List a -> List a
21+
Lin <>> xs = xs
22+
(sx :< x) <>> xs = sx <>> x :: xs
23+
24+
Cast (SnocList a) (List a) where
25+
cast sx = sx <>> []
26+
27+
Cast (List a) (SnocList a) where
28+
cast xs = Lin <>< xs
29+
30+
||| Transform to a list but keeping the contents in the spine order (term depth).
31+
public export
32+
asList : SnocList type -> List type
33+
asList = (reverse . cast)
34+
35+
36+
public export
37+
Eq a => Eq (SnocList a) where
38+
(==) Lin Lin = True
39+
(==) (sx :< x) (sy :< y) = x == y && sx == sy
40+
(==) _ _ = False
41+
42+
43+
public export
44+
Ord a => Ord (SnocList a) where
45+
compare Lin Lin = EQ
46+
compare Lin (sx :< x) = LT
47+
compare (sx :< x) Lin = GT
48+
compare (sx :< x) (sy :< y)
49+
= case compare sx sy of
50+
EQ => compare x y
51+
c => c
52+
53+
||| True iff input is Lin
54+
public export
55+
isLin : SnocList a -> Bool
56+
isLin Lin = True
57+
isLin (sx :< x) = False
58+
59+
||| True iff input is (:<)
60+
public export
61+
isSnoc : SnocList a -> Bool
62+
isSnoc Lin = False
63+
isSnoc (sx :< x) = True
64+
65+
public export
66+
(++) : (sx, sy : SnocList a) -> SnocList a
67+
(++) sx Lin = sx
68+
(++) sx (sy :< y) = (sx ++ sy) :< y
69+
70+
public export
71+
length : SnocList a -> Nat
72+
length Lin = Z
73+
length (sx :< x) = length sx + 1
74+
75+
export
76+
Show a => Show (SnocList a) where
77+
show xs = "[< " ++ show' "" xs ++ "]"
78+
where
79+
show' : String -> SnocList a -> String
80+
show' acc Lin = acc
81+
show' acc (Lin :< x)= show x ++ acc
82+
show' acc (xs :< x) = show' (", " ++ show x ++ acc) xs
83+
84+
85+
public export
86+
Functor SnocList where
87+
map f Lin = Lin
88+
map f (sx :< x) = (map f sx) :< (f x)
89+
90+
91+
public export
92+
Semigroup (SnocList a) where
93+
(<+>) = (++)
94+
95+
public export
96+
Monoid (SnocList a) where
97+
neutral = Lin
98+
99+
100+
||| Check if something is a member of a list using the default Boolean equality.
101+
public export
102+
elem : Eq a => a -> SnocList a -> Bool
103+
elem x Lin = False
104+
elem x (sx :< y) = x == y || elem x sx

libs/base/base.ipkg

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ modules = Control.App,
4848
Data.IOArray.Prims,
4949
Data.IORef,
5050
Data.List,
51+
Data.SnocList,
5152
Data.List.Elem,
5253
Data.List.Views,
5354
Data.List.Quantifiers,

libs/prelude/Prelude/Basics.idr

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,3 +169,14 @@ data List a =
169169
(::) a (List a)
170170

171171
%name List xs, ys, zs
172+
173+
||| Snoc lists.
174+
public export
175+
data SnocList a =
176+
||| Empty snoc-list
177+
Lin
178+
179+
| ||| A non-empty snoc-list, consisting of the rest of the snoc-list and the final element.
180+
(:<) (SnocList a) a
181+
182+
%name SnocList sx, sy, sz

libs/prelude/Prelude/Ops.idr

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ infixr 4 ||
1111

1212
-- List and String operators
1313
infixr 7 ::, ++
14+
infixl 7 :<
1415

1516
-- Functor/Applicative/Monad/Algebra operators
1617
infixl 1 >>=, =<<, >>, >=>, <=<, <&>

src/Idris/Desugar.idr

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -353,6 +353,8 @@ mutual
353353
pure val
354354
desugarB side ps (PList fc nilFC args)
355355
= expandList side ps nilFC args
356+
desugarB side ps (PSnocList fc nilFC args)
357+
= expandSnocList side ps nilFC (reverse args)
356358
desugarB side ps (PPair fc l r)
357359
= do l' <- desugarB side ps l
358360
r' <- desugarB side ps r
@@ -448,6 +450,18 @@ mutual
448450
= pure $ apply (IVar consFC (UN "::"))
449451
[!(desugarB side ps x), !(expandList side ps nilFC xs)]
450452

453+
expandSnocList
454+
: {auto s : Ref Syn SyntaxInfo} ->
455+
{auto b : Ref Bang BangData} ->
456+
{auto c : Ref Ctxt Defs} ->
457+
{auto u : Ref UST UState} ->
458+
{auto m : Ref MD Metadata} ->
459+
Side -> List Name -> (nilFC : FC) -> List (FC, PTerm) -> Core RawImp
460+
expandSnocList side ps nilFC [] = pure (IVar nilFC (UN "Lin"))
461+
expandSnocList side ps nilFC ((consFC, x) :: xs)
462+
= pure $ apply (IVar consFC (UN ":<"))
463+
[!(expandSnocList side ps nilFC xs) , !(desugarB side ps x)]
464+
451465
addFromString : {auto c : Ref Ctxt Defs} ->
452466
FC -> RawImp -> Core RawImp
453467
addFromString fc tm

src/Idris/DocString.idr

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,7 @@ getDocsForPTerm (PPrimVal _ constant) = getDocsForPrimitive constant
287287
getDocsForPTerm (PType _) = pure ["Type : Type\n\tThe type of all types is Type. The type of Type is Type."]
288288
getDocsForPTerm (PString _ _) = pure ["String Literal\n\tDesugars to a fromString call"]
289289
getDocsForPTerm (PList _ _ _) = pure ["List Literal\n\tDesugars to (::) and Nil"]
290+
getDocsForPTerm (PSnocList _ _ _) = pure ["SnocList Literal\n\tDesugars to (:<) and Empty"]
290291
getDocsForPTerm (PPair _ _ _) = pure ["Pair Literal\n\tDesugars to MkPair or Pair"]
291292
getDocsForPTerm (PDPair _ _ _ _ _) = pure ["Dependant Pair Literal\n\tDesugars to MkDPair or DPair"]
292293
getDocsForPTerm (PUnit _) = pure ["Unit Literal\n\tDesugars to MkUnit or Unit"]

src/Idris/IDEMode/CaseSplit.idr

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ toStrUpdate (UN n, term)
4949
bracket : PTerm -> PTerm
5050
bracket tm@(PRef _ _) = tm
5151
bracket tm@(PList _ _ _) = tm
52+
bracket tm@(PSnocList _ _ _) = tm
5253
bracket tm@(PPair _ _ _) = tm
5354
bracket tm@(PUnit _) = tm
5455
bracket tm@(PComprehension _ _ _) = tm

src/Idris/Parser.idr

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -384,7 +384,7 @@ mutual
384384
decorateKeywords fname xs
385385
pure (PRange fc (fst rstate) (snd rstate) y.val)
386386

387-
listExpr : FileName -> WithBounds t -> IndentInfo -> Rule PTerm
387+
listExpr : FileName -> WithBounds () -> IndentInfo -> Rule PTerm
388388
listExpr fname s indents
389389
= do b <- bounds (do ret <- expr pnowith fname indents
390390
decoratedSymbol fname "|"
@@ -407,6 +407,26 @@ mutual
407407
nilFC = if null xs then fc else boundToFC fname b
408408
in PList fc nilFC (map (\ t => (boundToFC fname t, t.val)) xs))
409409

410+
snocListExpr : FileName -> WithBounds () -> IndentInfo -> Rule PTerm
411+
snocListExpr fname s indents
412+
= {- TODO: comprehension -}
413+
do mHeadTail <- optional $ do
414+
hd <- many $ do x <- expr pdef fname indents
415+
b <- bounds (symbol ",")
416+
pure (x <$ b)
417+
tl <- expr pdef fname indents
418+
pure (hd, tl)
419+
{- TODO: reverse ranges -}
420+
b <- bounds (symbol "]")
421+
pure $
422+
let xs : List (WithBounds PTerm)
423+
= case mHeadTail of
424+
Nothing => []
425+
Just (hd,tl) => hd ++ [ tl <$ b]
426+
fc = boundToFC fname (mergeBounds s b)
427+
nilFC = ifThenElse (null xs) fc (boundToFC fname s)
428+
in PSnocList fc nilFC (map (\ t => (boundToFC fname t, t.val)) xs) --)
429+
410430
nonEmptyTuple : FileName -> WithBounds t -> IndentInfo -> PTerm -> Rule PTerm
411431
nonEmptyTuple fname s indents e
412432
= do vals <- some $ do b <- bounds (symbol ",")
@@ -492,7 +512,9 @@ mutual
492512
pure (PUnquote (boundToFC fname b) b.val)
493513
<|> do start <- bounds (symbol "(")
494514
bracketedExpr fname start indents
495-
<|> do start <- bounds (symbol "[")
515+
<|> do start <- bounds (symbol "[<")
516+
snocListExpr fname start indents
517+
<|> do start <- bounds (symbol "[>" <|> symbol "[")
496518
listExpr fname start indents
497519
<|> do b <- bounds (decoratedSymbol fname "!" *> simpleExpr fname indents)
498520
pure (PBang (virtualiseFC $ boundToFC fname b) b.val)

0 commit comments

Comments
 (0)