pub struct HCons<H, T> {
pub head: H,
pub tail: T,
}
Expand description
Represents the most basic non-empty HList. Its value is held in head
while its tail is another HList.
Fields§
§head: H
§tail: T
Implementations§
source§impl<Head, Tail> HCons<Head, Tail>
impl<Head, Tail> HCons<Head, Tail>
sourcepub fn sculpt<Ts, Indices>(
self,
) -> (Ts, <HCons<Head, Tail> as Sculptor<Ts, Indices>>::Remainder)
pub fn sculpt<Ts, Indices>( self, ) -> (Ts, <HCons<Head, Tail> as Sculptor<Ts, Indices>>::Remainder)
Consume the current HList and return an HList with the requested shape.
sculpt
allows us to extract/reshape/sculpt the current HList into another shape,
provided that the requested shape’s types are are contained within the current HList.
The Indices
type parameter allows the compiler to figure out that Ts
and Self
can be morphed into each other.
§Examples
use frunk_core::{hlist, HList};
let h = hlist![9000, "joe", 41f32, true];
let (reshaped, remainder): (HList![f32, i32, &str], _) = h.sculpt();
assert_eq!(reshaped, hlist![41f32, 9000, "joe"]);
assert_eq!(remainder, hlist![true]);
Runsourcepub fn into_reverse(self) -> <HCons<Head, Tail> as IntoReverse>::Outputwhere
HCons<Head, Tail>: IntoReverse,
pub fn into_reverse(self) -> <HCons<Head, Tail> as IntoReverse>::Outputwhere
HCons<Head, Tail>: IntoReverse,
sourcepub fn map<F>(self, mapper: F) -> <HCons<Head, Tail> as HMappable<F>>::Output
pub fn map<F>(self, mapper: F) -> <HCons<Head, Tail> as HMappable<F>>::Output
Apply a function to each element of an HList.
This transforms some HList![A, B, C, ..., E]
into some
HList![T, U, V, ..., Z]
. A variety of types are supported
for the folder argument:
- An
hlist![]
of closures (one for each element). - A single closure (for mapping an HList that is homogenous).
- A single
Poly
.
§Examples
use frunk::HNil;
use frunk_core::hlist;
assert_eq!(HNil.map(HNil), HNil);
let h = hlist![1, false, 42f32];
// Sadly we need to help the compiler understand the bool type in our mapper
let mapped = h.to_ref().map(hlist![
|&n| n + 1,
|b: &bool| !b,
|&f| f + 1f32]);
assert_eq!(mapped, hlist![2, true, 43f32]);
// There is also a value-consuming version that passes values to your functions
// instead of just references:
let mapped2 = h.map(hlist![
|n| n + 3,
|b: bool| !b,
|f| f + 8959f32]);
assert_eq!(mapped2, hlist![4, true, 9001f32]);
Runsourcepub fn zip<Other>(
self,
other: Other,
) -> <HCons<Head, Tail> as HZippable<Other>>::Zipped
pub fn zip<Other>( self, other: Other, ) -> <HCons<Head, Tail> as HZippable<Other>>::Zipped
Zip two HLists together.
This zips a HList![A1, B1, ..., C1]
with a HList![A2, B2, ..., C2]
to make a HList![(A1, A2), (B1, B2), ..., (C1, C2)]
§Example
use frunk::HNil;
use frunk_core::hlist;
assert_eq!(HNil.zip(HNil), HNil);
let h1 = hlist![1, false, 42f32];
let h2 = hlist![true, "foo", 2];
let zipped = h1.zip(h2);
assert_eq!(zipped, hlist![
(1, true),
(false, "foo"),
(42f32, 2),
]);
Runsourcepub fn foldl<Folder, Acc>(
self,
folder: Folder,
acc: Acc,
) -> <HCons<Head, Tail> as HFoldLeftable<Folder, Acc>>::Outputwhere
HCons<Head, Tail>: HFoldLeftable<Folder, Acc>,
pub fn foldl<Folder, Acc>(
self,
folder: Folder,
acc: Acc,
) -> <HCons<Head, Tail> as HFoldLeftable<Folder, Acc>>::Outputwhere
HCons<Head, Tail>: HFoldLeftable<Folder, Acc>,
Perform a left fold over an HList.
This transforms some HList![A, B, C, ..., E]
into a single
value by visiting all of the elements in left-to-right order.
A variety of types are supported for the mapper argument:
- An
hlist![]
of closures (one for each element). - A single closure (for folding an HList that is homogenous).
- A single
Poly
.
The accumulator can freely change type over the course of the call.
When called with a list of N
functions, an expanded form of the
implementation with type annotations might look something like this:
let acc: Acc0 = init_value;
let acc: Acc1 = f1(acc, x1);
let acc: Acc2 = f2(acc, x2);
let acc: Acc3 = f3(acc, x3);
...
let acc: AccN = fN(acc, xN);
acc
Run§Examples
use frunk_core::hlist;
let nil = hlist![];
assert_eq!(nil.foldl(hlist![], 0), 0);
let h = hlist![1, false, 42f32];
let folded = h.to_ref().foldl(
hlist![
|acc, &i| i + acc,
|acc, b: &bool| if !b && acc > 42 { 9000f32 } else { 0f32 },
|acc, &f| f + acc
],
1
);
assert_eq!(42f32, folded);
// There is also a value-consuming version that passes values to your folding
// functions instead of just references:
let folded2 = h.foldl(
hlist![
|acc, i| i + acc,
|acc, b: bool| if !b && acc > 42 { 9000f32 } else { 0f32 },
|acc, f| f + acc
],
8918
);
assert_eq!(9042f32, folded2)
Runsourcepub fn foldr<Folder, Init>(
self,
folder: Folder,
init: Init,
) -> <HCons<Head, Tail> as HFoldRightable<Folder, Init>>::Outputwhere
HCons<Head, Tail>: HFoldRightable<Folder, Init>,
pub fn foldr<Folder, Init>(
self,
folder: Folder,
init: Init,
) -> <HCons<Head, Tail> as HFoldRightable<Folder, Init>>::Outputwhere
HCons<Head, Tail>: HFoldRightable<Folder, Init>,
Perform a right fold over an HList.
This transforms some HList![A, B, C, ..., E]
into a single
value by visiting all of the elements in reverse order.
A variety of types are supported for the mapper argument:
- An
hlist![]
of closures (one for each element). - A single closure (for folding an HList that is homogenous), taken by reference.
- A single
Poly
.
The accumulator can freely change type over the course of the call.
§Comparison to foldl
While the order of element traversal in foldl
may seem more natural,
foldr
does have its use cases, in particular when it is used to build
something that reflects the structure of the original HList (such as
folding an HList of Option
s into an Option
of an HList).
An implementation of such a function using foldl
will tend to
reverse the list, while foldr
will tend to preserve its order.
The reason for this is because foldr
performs what is known as
“structural induction;” it can be understood as follows:
- Write out the HList in terms of
h_cons
andHNil
. - Substitute each
h_cons
with a function, and substituteHNil
withinit
the list:
h_cons(x1, h_cons(x2, h_cons(x3, ...h_cons(xN, HNil)...)))
becomes:
f1( x1, f2( x2, f3( x3, ... fN( xN, init)...)))
§Examples
use frunk_core::hlist;
let nil = hlist![];
assert_eq!(nil.foldr(hlist![], 0), 0);
let h = hlist![1, false, 42f32];
let folded = h.foldr(
hlist![
|acc, i| i + acc,
|acc, b: bool| if !b && acc > 42f32 { 9000 } else { 0 },
|acc, f| f + acc
],
1f32
);
assert_eq!(9001, folded)
Runsource§impl<Head, Tail> HCons<Head, Tail>
impl<Head, Tail> HCons<Head, Tail>
sourcepub fn get<T, Index>(&self) -> &T
pub fn get<T, Index>(&self) -> &T
Borrow an element by type from an HList.
§Examples
use frunk_core::hlist;
let h = hlist![1i32, 2u32, "hello", true, 42f32];
// Often, type inference can figure out the type you want.
// You can help guide type inference when necessary by
// using type annotations.
let b: &bool = h.get();
if !b { panic!("no way!") };
// If space is tight, you can also use turbofish syntax.
// The Index is still left to type inference by using `_`.
match *h.get::<u32, _>() {
2 => { }
_ => panic!("it can't be!!"),
}
Runsourcepub fn pluck<T, Index>(
self,
) -> (T, <HCons<Head, Tail> as Plucker<T, Index>>::Remainder)
pub fn pluck<T, Index>( self, ) -> (T, <HCons<Head, Tail> as Plucker<T, Index>>::Remainder)
Remove an element by type from an HList.
The remaining elements are returned along with it.
§Examples
use frunk_core::hlist;
let list = hlist![1, "hello", true, 42f32];
// Often, type inference can figure out the target type.
let (b, list): (bool, _) = list.pluck();
assert!(b);
// When type inference will not suffice, you can use a turbofish.
// The Index is still left to type inference by using `_`.
let (s, list) = list.pluck::<i32, _>();
// Each time we plucked, we got back a remainder.
// Let's check what's left:
assert_eq!(list, hlist!["hello", 42.0])
Runsourcepub fn into_tuple2(
self,
) -> (<HCons<Head, Tail> as IntoTuple2>::HeadType, <HCons<Head, Tail> as IntoTuple2>::TailOutput)where
HCons<Head, Tail>: IntoTuple2,
pub fn into_tuple2(
self,
) -> (<HCons<Head, Tail> as IntoTuple2>::HeadType, <HCons<Head, Tail> as IntoTuple2>::TailOutput)where
HCons<Head, Tail>: IntoTuple2,
Turns an HList into nested Tuple2s, which are less troublesome to pattern match and have a nicer type signature.
§Examples
use frunk_core::hlist;
let h = hlist![1, "hello", true, 42f32];
// We now have a much nicer pattern matching experience
let (first,(second,(third, fourth))) = h.into_tuple2();
assert_eq!(first , 1);
assert_eq!(second, "hello");
assert_eq!(third , true);
assert_eq!(fourth, 42f32);
RunTrait Implementations§
source§impl<K, V, Tail> ByNameFieldPlucker<K, Here> for HCons<Field<K, V>, Tail>
impl<K, V, Tail> ByNameFieldPlucker<K, Here> for HCons<Field<K, V>, Tail>
Implementation when the pluck target key is in the head.
type TargetValue = V
type Remainder = Tail
source§fn pluck_by_name(
self,
) -> (Field<K, <HCons<Field<K, V>, Tail> as ByNameFieldPlucker<K, Here>>::TargetValue>, <HCons<Field<K, V>, Tail> as ByNameFieldPlucker<K, Here>>::Remainder)
fn pluck_by_name( self, ) -> (Field<K, <HCons<Field<K, V>, Tail> as ByNameFieldPlucker<K, Here>>::TargetValue>, <HCons<Field<K, V>, Tail> as ByNameFieldPlucker<K, Here>>::Remainder)
source§impl<Head, Tail, K, TailIndex> ByNameFieldPlucker<K, There<TailIndex>> for HCons<Head, Tail>where
Tail: ByNameFieldPlucker<K, TailIndex>,
impl<Head, Tail, K, TailIndex> ByNameFieldPlucker<K, There<TailIndex>> for HCons<Head, Tail>where
Tail: ByNameFieldPlucker<K, TailIndex>,
Implementation when the pluck target key is in the tail.
type TargetValue = <Tail as ByNameFieldPlucker<K, TailIndex>>::TargetValue
type Remainder = HCons<Head, <Tail as ByNameFieldPlucker<K, TailIndex>>::Remainder>
source§fn pluck_by_name(
self,
) -> (Field<K, <HCons<Head, Tail> as ByNameFieldPlucker<K, There<TailIndex>>>::TargetValue>, <HCons<Head, Tail> as ByNameFieldPlucker<K, There<TailIndex>>>::Remainder)
fn pluck_by_name( self, ) -> (Field<K, <HCons<Head, Tail> as ByNameFieldPlucker<K, There<TailIndex>>>::TargetValue>, <HCons<Head, Tail> as ByNameFieldPlucker<K, There<TailIndex>>>::Remainder)
source§impl<Head, Tail, Out, NHead, NTail> CoproductEmbedder<Out, HCons<NHead, NTail>> for Coproduct<Head, Tail>where
Out: CoprodInjector<Head, NHead>,
Tail: CoproductEmbedder<Out, NTail>,
impl<Head, Tail, Out, NHead, NTail> CoproductEmbedder<Out, HCons<NHead, NTail>> for Coproduct<Head, Tail>where
Out: CoprodInjector<Head, NHead>,
Tail: CoproductEmbedder<Out, NTail>,
source§impl<F, R, FTail, CH, CTail> CoproductFoldable<HCons<F, FTail>, R> for Coproduct<CH, CTail>where
F: FnOnce(CH) -> R,
CTail: CoproductFoldable<FTail, R>,
impl<F, R, FTail, CH, CTail> CoproductFoldable<HCons<F, FTail>, R> for Coproduct<CH, CTail>where
F: FnOnce(CH) -> R,
CTail: CoproductFoldable<FTail, R>,
source§impl<'a, F, R, MapperTail, CH, CTail> CoproductMappable<&'a HCons<F, MapperTail>> for Coproduct<CH, CTail>
impl<'a, F, R, MapperTail, CH, CTail> CoproductMappable<&'a HCons<F, MapperTail>> for Coproduct<CH, CTail>
Implementation for mapping a Coproduct using a &hlist!
.
type Output = Coproduct<R, <CTail as CoproductMappable<&'a MapperTail>>::Output>
source§impl<'a, F, R, MapperTail, CH, CTail> CoproductMappable<&'a mut HCons<F, MapperTail>> for Coproduct<CH, CTail>
impl<'a, F, R, MapperTail, CH, CTail> CoproductMappable<&'a mut HCons<F, MapperTail>> for Coproduct<CH, CTail>
Implementation for mapping a Coproduct using a &mut hlist!
.
type Output = Coproduct<R, <CTail as CoproductMappable<&'a mut MapperTail>>::Output>
source§impl<F, R, MapperTail, CH, CTail> CoproductMappable<HCons<F, MapperTail>> for Coproduct<CH, CTail>where
F: FnOnce(CH) -> R,
CTail: CoproductMappable<MapperTail>,
impl<F, R, MapperTail, CH, CTail> CoproductMappable<HCons<F, MapperTail>> for Coproduct<CH, CTail>where
F: FnOnce(CH) -> R,
CTail: CoproductMappable<MapperTail>,
Implementation for mapping a Coproduct using an hlist!
.