Skip to content

Commit d5b346c

Browse files
committed
Adding uncons
1 parent 775ad37 commit d5b346c

3 files changed

Lines changed: 80 additions & 2 deletions

File tree

CHANGELOG.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ All notable changes to this project will be documented in this file.
44
The format is based on [Keep a Changelog](http://keepachangelog.com/).
55

66
## [Unreleased]
7-
8-
---
7+
### Added
8+
- `Uncons`, for destructuring an `Iterable` into its head and tail
99

1010
## [1.6.1] - 2017-06-17
1111
### Changed
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
package com.jnape.palatable.lambda.functions.builtin.fn1;
2+
3+
import com.jnape.palatable.lambda.adt.hlist.Tuple2;
4+
import com.jnape.palatable.lambda.functions.Fn1;
5+
6+
import java.util.Optional;
7+
8+
import static com.jnape.palatable.lambda.adt.hlist.HList.tuple;
9+
import static com.jnape.palatable.lambda.functions.builtin.fn1.Head.head;
10+
import static com.jnape.palatable.lambda.functions.builtin.fn1.Tail.tail;
11+
12+
/**
13+
* Destructure an {@link Iterable} into a {@link Tuple2} of its head and tail, wrapped in an {@link Optional}. If the
14+
* {@link Iterable} is empty, returns <code>Optional.empty()</code>.
15+
*
16+
* @param <A> the Iterable element type
17+
*/
18+
public final class Uncons<A> implements Fn1<Iterable<A>, Optional<Tuple2<A, Iterable<A>>>> {
19+
20+
private static final Uncons INSTANCE = new Uncons();
21+
22+
private Uncons() {
23+
}
24+
25+
@Override
26+
public Optional<Tuple2<A, Iterable<A>>> apply(Iterable<A> as) {
27+
return head(as).map(a -> tuple(a, tail(as)));
28+
}
29+
30+
@SuppressWarnings("unchecked")
31+
public static <A> Uncons<A> uncons() {
32+
return INSTANCE;
33+
}
34+
35+
public static <A> Optional<Tuple2<A, Iterable<A>>> uncons(Iterable<A> as) {
36+
return Uncons.<A>uncons().apply(as);
37+
}
38+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
package com.jnape.palatable.lambda.functions.builtin.fn1;
2+
3+
import com.jnape.palatable.lambda.adt.hlist.Tuple2;
4+
import com.jnape.palatable.traitor.annotations.TestTraits;
5+
import com.jnape.palatable.traitor.runners.Traits;
6+
import org.junit.Test;
7+
import org.junit.runner.RunWith;
8+
import testsupport.traits.EmptyIterableSupport;
9+
10+
import java.util.Optional;
11+
12+
import static com.jnape.palatable.lambda.functions.builtin.fn1.Uncons.uncons;
13+
import static java.util.Arrays.asList;
14+
import static java.util.Collections.emptyList;
15+
import static org.junit.Assert.assertEquals;
16+
import static org.junit.Assert.assertThat;
17+
import static testsupport.matchers.IterableMatcher.iterates;
18+
19+
@RunWith(Traits.class)
20+
public class UnconsTest {
21+
22+
@TestTraits({EmptyIterableSupport.class})
23+
public Uncons testSubject() {
24+
return uncons();
25+
}
26+
27+
@Test
28+
public void nonEmptyIterable() {
29+
Iterable<Integer> numbers = asList(1, 2, 3);
30+
Tuple2<Integer, Iterable<Integer>> headAndTail = uncons(numbers).orElseThrow(AssertionError::new);
31+
32+
assertEquals((Integer) 1, headAndTail._1());
33+
assertThat(headAndTail._2(), iterates(2, 3));
34+
}
35+
36+
@Test
37+
public void emptyIterable() {
38+
assertEquals(Optional.empty(), uncons(emptyList()));
39+
}
40+
}

0 commit comments

Comments
 (0)