trecursive_generic_in_compiles.nim 2.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. discard """
  2. action: compile
  3. """
  4. # bug #3313
  5. import unittest, sugar
  6. {.experimental: "notnil".}
  7. type
  8. ListNodeKind = enum
  9. lnkNil, lnkCons
  10. List*[T] = ref object
  11. ## List ADT
  12. case kind: ListNodeKind
  13. of lnkNil:
  14. discard
  15. of lnkCons:
  16. value: T
  17. next: List[T] not nil
  18. proc Cons*[T](head: T, tail: List[T]): List[T] =
  19. ## Constructs non empty list
  20. List[T](kind: lnkCons, value: head, next: tail)
  21. proc Nil*[T](): List[T] =
  22. ## Constructs empty list
  23. List[T](kind: lnkNil)
  24. proc head*[T](xs: List[T]): T =
  25. ## Returns list's head
  26. xs.value
  27. # TODO
  28. # proc headOption*[T](xs: List[T]): Option[T] = ???
  29. proc tail*[T](xs: List[T]): List[T] =
  30. ## Returns list's tail
  31. case xs.kind
  32. of lnkCons: xs.next
  33. else: xs
  34. proc isEmpty*(xs: List): bool =
  35. ## Checks if list is empty
  36. xs.kind == lnkNil
  37. proc `==`*[T](xs, ys: List[T]): bool =
  38. ## Compares two lists
  39. if (xs.isEmpty, ys.isEmpty) == (true, true): true
  40. elif (xs.isEmpty, ys.isEmpty) == (false, false): xs.head == ys.head and xs.tail == ys.tail
  41. else: false
  42. proc asList*[T](xs: varargs[T]): List[T] =
  43. ## Creates list from varargs
  44. proc initListImpl(i: int, xs: openArray[T]): List[T] =
  45. if i > high(xs):
  46. Nil[T]()
  47. else:
  48. Cons(xs[i], initListImpl(i+1, xs))
  49. initListImpl(0, xs)
  50. proc foldRight*[T,U](xs: List[T], z: U, f: (T, U) -> U): U =
  51. case xs.isEmpty
  52. of true: z
  53. else: f(xs.head, xs.tail.foldRight(z, f))
  54. proc dup*[T](xs: List[T]): List[T] =
  55. ## Duplicates the list
  56. xs.foldRight(Nil[T](), (x: T, xs: List[T]) => Cons(x, xs))
  57. type
  58. ListFormat = enum
  59. lfADT, lfSTD
  60. proc asString[T](xs: List[T], f = lfSTD): string =
  61. proc asAdt(xs: List[T]): string =
  62. case xs.isEmpty
  63. of true: "Nil"
  64. else: "Cons(" & $xs.head & ", " & xs.tail.asAdt & ")"
  65. proc asStd(xs: List[T]): string =
  66. "List(" & xs.foldLeft("", (s: string, v: T) =>
  67. (if s == "": $v else: s & ", " & $v)) & ")"
  68. case f
  69. of lfADT: xs.asAdt
  70. else: xs.asStd
  71. proc `$`*[T](xs: List[T]): string =
  72. ## Converts list to string
  73. result = xs.asString
  74. proc foldLeft*[T,U](xs: List[T], z: U, f: (U, T) -> U): U =
  75. case xs.isEmpty
  76. of true: z
  77. else: foldLeft(xs.tail, f(z, xs.head), f)