fabiommendes/elm-tape/1.0.0

Tape

A linear structure with a cursor pointing to some specific element. Tapes cannot be empty.

type Tape a

Base iterator type

Create

create : List a -> a -> List a -> Tape a

Create a tape from the left, head, and right parts.

The tape is conceptually equivalent to the list left ++ [head] ++ right and has a cursor that points to the tape head.

create [ "a", "b" ] "c" [ "d", "e" ]
    |> show identity
    --> "[ a, b, => c, d, e ]"
fromList : List a -> Maybe (Tape a)

Try to create tape from List. Empty lists return Nothing.

(fromList [ 1, 2, 3 ]
    |> Maybe.map toList)
    --> Just [ 1, 2, 3 ]
fromListOrDefault : a -> List a -> Tape a

Create a tape from List or a singleton tape with the given default value.

fromListOrDefault 0 [ 1, 2, 3 ]
    |> toList
    --> [ 1, 2, 3 ]
fromParts : List a -> a -> List a -> Tape a

Construct tape from left and right tails.

fromParts (tail Left tape) (head tape) (tail Right tape) ==> tape
singleton : a -> Tape a

Create a tape with only one element

repeat : Int -> Int -> a -> Tape a

Create a tape with n copies of a value and tries to place m of them before the head.

repeat 0 behaves similarly to List.repeat, creating a tape with n elements pointing to the first element.

Empty negative n are ignored, returning a tape with a single element.

repeat 2 5 "a"
    |> show identity
    --> "[ a, a, => a, a, a ]"
range : Int -> Int -> Tape Int

Create a tape of numbers, every element increasing by one.

The arguments are the lowest and highest numbers that should be on the tape.

range 0 5
    |> toList
    --> [ 0, 1, 2, 3, 4, 5 ]

Move operations

read : Tape a -> a

Read element on the current position.

create [1, 2] 3 [4, 5]
    |> read
    --> 3
write : a -> Tape a -> Tape a

Write element to the tape's current position.

create ["a", "b"] "c" ["d", "e"]
    |> write "changed"
    |> show identity
    --> "[ a, b, => changed, d, e ]"
advance : Tape a -> Tape a

Advance tape to the last element

create ["a", "b"] "c" ["d", "e"]
    |> advance
    |> show identity
    --> "[ a, b, c, d, => e ]"
rewind : Tape a -> Tape a

Rewind tape so the head points to the first element

create ["a", "b"] "c" ["d", "e"]
    |> rewind
    |> show identity
    --> "[ => a, b, c, d, e ]"
left : Int -> Tape a -> Tape a

Move at most n positions to the left.

Negative steps move to the right.

create ["a", "b", "c"] "d" ["e"]
    |> left 2
    |> show identity
    --> "[ a, => b, c, d, e ]"
undo : Tape a -> Tape a

An alias to left 1 that is more idiomatic when using the tape as a history container.

create ["a", "b", "c"] "d" ["e"]
    |> undo
    |> show identity
        --> "[ a, b, => c, d, e ]"
redo : Tape a -> Tape a

An alias to right 1 that is more idiomatic when using the tape as a history container.

create ["a", "b", "c"] "d" ["e"]
    |> redo
    |> show identity
        --> "[ a, b, c, d, => e ]"

Advanced move operators

type How a
= Cycle Int
| Default ( a, Int )
| Condition (a -> Bool)
| Carry Int

Declare how to move in the tape.

leftWith : How a -> Tape a -> Tape a

Move head to the left according to strategy

create ["a", "b"] "c" ["d", "e"]
    |> leftWith (Cycle 3)
    |> show identity
    --> "[ a, b, c, d, => e ]"


create ["a", "b"] "c" ["d", "e"]
     |> leftWith (Default ("?", 4))
     |> show identity
     --> "[ => ?, ?, a, b, c, d, e ]"


create ["a", "b"] "c" ["d", "e"]
     |> leftWith (Condition ((/=) "b"))
     |> show identity
     --> "[ a, => b, c, d, e ]"


create ["a", "b"] "cc" ["d", "e"]
    |> leftWith (Carry 2)
    |> show identity
    --> "[ => cc, a, b, d, e ]"
rightWith : How a -> Tape a -> Tape a

Move head to the right according to strategy

create ["a", "b"] "c" ["d", "e"]
    |> rightWith (Cycle 3)
    |> show identity
    --> "[ => a, b, c, d, e ]"


create ["a", "b"] "c" ["d", "e"]
        |> rightWith (Default ("?", 4))
        |> show identity
        --> "[ a, b, c, d, e, ?, => ? ]"


create ["a", "b"] "c" ["d", "e"]
        |> rightWith (Condition ((/=) "b"))
        |> show identity
        --> "[ a, b, c, d, => e ]"


create ["a", "b"] "c" ["d", "e"]
    |> rightWith (Carry 2)
    |> show identity
    --> "[ a, b, d, e, => c ]"
tryLeft : Int -> Tape a -> Maybe (Tape a)

Try to move to the left.

Return Nothing if the tape would overflow on the leftmost position.

create ["a"] "b" ["c", "d", "e"]
    |> tryLeft 2
    --> Nothing
tryRight : Int -> Tape a -> Maybe (Tape a)

Try to move to the right.

Return Nothing if the tape would overflow on the rightmost position.

create ["a", "b"] "c" ["d"]
    |> tryRight 2
    --> Nothing
pushLeft : a -> Tape a -> Tape a

Push element to the left of the current head and move the cursor to it.

create ["a", "b"] "c" ["d", "e"]
    |> pushLeft "changed"
    |> show identity
    --> "[ a, b, => changed, c, d, e ]"
pushRight : a -> Tape a -> Tape a

Push element to the right of the current head and move the cursor to it.

create ["a", "b"] "c" ["d", "e"]
    |> pushRight "changed"
    |> show identity
    --> "[ a, b, c, => changed, d, e ]"

Mapping

map : (a -> b) -> Tape a -> Tape b

Apply a function to every element of a tape.

create ["a", "b"] "c" ["d", "e"]
    |> map String.toUpper
    |> show identity
    --> "[ A, B, => C, D, E ]"
map2 : (a -> b -> result) -> Tape a -> Tape b -> Tape result

Combine two tapes with function.

It keeps the smallest left and right tails of each tape.

(map2 (++)
    (create ["a", "b"] "c" ["d", "e"])
    (repeat 1 5 "x")
)
    |> show identity
    --> "[ bx, => cx, dx, ex ]"
map3 : (a -> b -> c -> result) -> Tape a -> Tape b -> Tape c -> Tape result

Generalize map for 3 tapes

(a -> b -> c -> d -> result)
-> Tape a
-> Tape b
-> Tape c
-> Tape d
-> Tape result

Generalize map for 4 tapes

(a -> b -> c -> d -> e -> result)
-> Tape a
-> Tape b
-> Tape c
-> Tape d
-> Tape e
-> Tape result

Generalize map for 5 tapes

indexedMap : (Int -> a -> b) -> Tape a -> Tape b

Same as map but the function is also applied to the index of each element.

The head has an index of zero and the left hand side of the tape is indexed with negative numbers.

create ["a", "b"] "c" ["d", "e"]
    |> indexedMap (\i x -> String.fromInt i ++ x)
    |> show identity
    --> "[ -2a, -1b, => 0c, 1d, 2e ]"
positionalMap : (Int -> a -> b) -> Tape a -> Tape b

Similar to indexedMap, but uses the position of each element, which is equivalent to the index of a rewinded tape.

create ["a", "b"] "c" ["d", "e"]
    |> positionalMap (\i x -> String.fromInt i ++ x)
    |> show identity
    --> "[ 0a, 1b, => 2c, 3d, 4e ]"

Transforms

reverse : Tape a -> Tape a

Flip a tape around the head.

create ["a", "b"] "c" ["d", "e"]
    |> reverse
    |> show identity
    --> "[ e, d, => c, b, a ]"
sort : Tape comparable -> Tape comparable

Sort values from lowest to highest

Head moves to keep track of current element.

create ["d"] "c" ["a", "e", "b"]
    |> sort
    |> show identity
    --> "[ a, b, => c, d, e ]"
sortBy : (a -> comparable) -> Tape a -> Tape a

Sort values by a derived property.

Head moves to keep track of current element.

create ["d"] "cc" ["a", "eee", "bb"]
    |> sortBy String.length
    |> show identity
    --> "[ d, a, => cc, bb, eee ]"
sortWith : (a -> a -> Order) -> Tape a -> Tape a

Sort values with a custom comparison function.

Head moves to keep track of current element.

intersperse : a -> Tape a -> Tape a

Places the given value between all members of the given tape.

create ["a", "b"] "c" ["d", "e"]
    |> intersperse "x"
    |> show identity
    --> "[ a, x, b, x, => c, x, d, x, e ]"

Sub-tapes

= Left
| Right
| LeftTail
| Backwards
| BackwardsTail
| RightTail
| Head
| Tails
| InsideOut
| All

The direction enum selects parts of the tape that shall be extracted/modified.

Each function might interpret each direction slightly differently. Check the documentation for more details.

select : Direction -> Tape a -> List a

Select parts of a tape and return it as a list

create ["a", "b"] "c" ["d", "e"]
    |> select All
    --> [ "a", "b", "c", "d", "e" ]


create ["a", "b"] "c" ["d", "e"]
    |> select Left
    --> [ "a", "b", "c" ]


create ["a", "b"] "c" ["d", "e"]
    |> select Backwards
    --> [ "c", "b", "a" ]


create ["a", "b"] "c" ["d", "e"]
    |> select Head
    --> [ "c" ]


create ["a", "b"] "c" ["d", "e"]
    |> select Tails
    --> [ "a", "b", "d", "e" ]
update : Direction -> (a -> a) -> Tape a -> Tape a

A partial map on the tape, preserving the types of elements.

We can specify a direction to update from the head

create ["a", "b"] "c" ["d", "e"]
    |> update Right String.toUpper
    |> show identity
    --> "[ a, b, => C, D, E ]"

The direction can be one of the following:

- `Left` - only the left part is modified, including the head.
- `Right` - only the right part is modified, including the head.
- `LeftTail` - only the left part is modified, excluding the head.
- `RightTail` - only the right part is modified, excluding the head.
- `Backwards` - same as Left.
- `BackwardsTail` - same as LeftTail.
- `Head` - only the head is modified.
- `Tails` - modify everything exept the head.
- `InsideOut` - like All.
- `All` - all elements are modified.
take : Direction -> Int -> Tape a -> Tape a

Take elements from one specific direction on the tape

filter : Direction -> (a -> Bool) -> Tape a -> Tape a

Filter the given selection of tape with predicate.

Filter never removes the head, which makes filter Head a no-op and filter DirectoinTail and filter Direction equivalent.

If you want to filter the head, convert to a list before

Deconstruction

unzip : Tape ( a, b ) -> ( Tape a, Tape b )

Decompose a tape of tuples into a tuple of tapes.

create [("a", 1), ("b", 2)] ("c", 3) [("d", 4), ("e", 5)]
    |> unzip
    |> Tuple.mapBoth (show identity) (show String.fromInt)
    --> ( "[ a, b, => c, d, e ]", "[ 1, 2, => 3, 4, 5 ]" )
parts : Tape a -> ( List a, a, List a )

Separate the list in the (left, head, tail) parts.

The parts can be assembled back together with create left head tail

Conversions

toList : Tape a -> List a

Converts tape to list

create ["a", "b"] "c" ["d", "e"]
    |> toList
    --> ["a", "b", "c", "d", "e"]
show : (a -> String) -> Tape a -> String

Show tape as string, with emphasis on head element

Summarizing and folding

foldr : (a -> b -> b) -> b -> Tape a -> b

Reduce a tape from the right.

It has the same effect as reducing the equivalent list.

create ["a", "b"] "c" ["d", "e"]
    |> foldr (++) "$"
    --> "abcde$"
foldl : (a -> b -> b) -> b -> Tape a -> b

Reduce a tape from the left.

It has the same effect as reducing the equivalent list.

create ["a", "b"] "c" ["d", "e"]
    |> foldl (++) "$"
    --> "edcba$"
reduce : (a -> a -> a) -> Tape a -> a

Reduce tape applying binary operator.

Similar to a left fold, but it does not require an initial accumulator.

create ["a", "b"] "c" ["d", "e"]
    |> reduce (++)
    --> "abcde"


create [] "c" ["d", "e"]
    |> reduce (++)
    --> "cde"
maximum : Tape comparable -> comparable

Find the maximum element in a non-empty list.

minimum : Tape comparable -> comparable

Find the minimum element in a non-empty list.

sum : Tape number -> number

Get the sum of the list elements.

product : Tape number -> number

Get the product of the list elements.

all : (a -> Bool) -> Tape a -> Bool

Determine if all elements satisfy some test.

create ["a", "b"] "c" ["d", "e"]
    |> all (\x -> String.length x < 2)
    --> True
any : (a -> Bool) -> Tape a -> Bool

Determine if any element satisfy some test.

create ["a", "b"] "c" ["d", "e"]
    |> any (\x -> x == "e")
    --> True

Properties

length : Tape a -> Int

Determine the length of a tape.

create ["a", "b"] "c" ["d", "e"]
    |> length
    --> 5
position : Tape a -> Int

Determine the position of head.

Position corresponds to the number of steps we must move right from a rewinded tape.

create ["a", "b"] "c" ["d", "e"]
    |> position
    --> 2
member : a -> Tape a -> Bool

Figure out whether a tape contains a value.

create ["a", "b"] "c" ["d", "e"]
    |> member "b"
    --> True
isEmptyLeft : Tape a -> Bool

True if tape has no elements to the left o head

isEmptyRight : Tape a -> Bool

True if tape has no elements to the right o head

elemIndex : a -> Tape a -> Maybe Int

Return index of element in tape

Elements left of head have negative indexes.