fp_library/types/
identity.rs

1//! Implementations for [`Identity`], a type that wraps a value.
2
3use crate::{
4	classes::{
5		Applicative, ApplyFirst, ApplySecond, ClonableFn, Foldable, Functor, Pointed,
6		Semiapplicative, Semimonad, Traversable, clonable_fn::ApplyClonableFn,
7	},
8	functions::{identity, map, pure},
9	hkt::{Apply0L1T, Kind0L1T},
10};
11
12/// Wraps a value.
13#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
14pub struct Identity<A>(pub A);
15
16pub struct IdentityBrand;
17
18impl Kind0L1T for IdentityBrand {
19	type Output<A> = Identity<A>;
20}
21
22impl Functor for IdentityBrand {
23	/// # Examples
24	///
25	/// ```
26	/// use fp_library::{brands::{IdentityBrand, RcFnBrand}, functions::{identity, map}, types::Identity};
27	/// use std::rc::Rc;
28	///
29	/// assert_eq!(
30	///     map::<RcFnBrand, IdentityBrand, _, _>(Rc::new(identity))(Identity(())),
31	///     Identity(())
32	/// );
33	/// ```
34	fn map<'a, ClonableFnBrand: 'a + ClonableFn, A: 'a, B: 'a>(
35		f: ApplyClonableFn<'a, ClonableFnBrand, A, B>
36	) -> ApplyClonableFn<'a, ClonableFnBrand, Apply0L1T<Self, A>, Apply0L1T<Self, B>> {
37		<ClonableFnBrand as ClonableFn>::new(move |fa: Apply0L1T<Self, _>| Identity(f(fa.0)))
38	}
39}
40
41impl Semiapplicative for IdentityBrand {
42	/// # Examples
43	///
44	/// ```
45	/// use fp_library::{brands::{IdentityBrand, RcFnBrand}, functions::{apply, identity}, types::Identity};
46	/// use std::rc::Rc;
47	///
48	/// assert_eq!(
49	///     apply::<RcFnBrand, IdentityBrand, _, _>(Identity(Rc::new(identity)))(Identity(())),
50	///     Identity(())
51	/// );
52	/// ```
53	fn apply<'a, ClonableFnBrand: 'a + ClonableFn, A: 'a + Clone, B: 'a>(
54		ff: Apply0L1T<Self, ApplyClonableFn<'a, ClonableFnBrand, A, B>>
55	) -> ApplyClonableFn<'a, ClonableFnBrand, Apply0L1T<Self, A>, Apply0L1T<Self, B>> {
56		map::<ClonableFnBrand, Self, A, B>(ff.0)
57	}
58}
59
60impl ApplyFirst for IdentityBrand {
61	/// # Examples
62	///
63	/// ```
64	/// use fp_library::{brands::{IdentityBrand, RcFnBrand}, functions::{apply_first, identity}, types::Identity};
65	/// use std::rc::Rc;
66	///
67	/// assert_eq!(
68	///     apply_first::<RcFnBrand, IdentityBrand, _, _>(Identity(true))(Identity(false)),
69	///     Identity(true)
70	/// );
71	/// ```
72	fn apply_first<'a, ClonableFnBrand: 'a + ClonableFn, A: 'a + Clone, B: Clone>(
73		fa: Apply0L1T<Self, A>
74	) -> ApplyClonableFn<'a, ClonableFnBrand, Apply0L1T<Self, B>, Apply0L1T<Self, A>> {
75		<ClonableFnBrand as ClonableFn>::new(move |_fb| fa.to_owned())
76	}
77}
78
79impl ApplySecond for IdentityBrand {
80	/// # Examples
81	///
82	/// ```
83	/// use fp_library::{brands::{IdentityBrand, RcFnBrand}, functions::{apply_second, identity}, types::Identity};
84	/// use std::rc::Rc;
85	///
86	/// assert_eq!(
87	///     apply_second::<RcFnBrand, IdentityBrand, _, _>(Identity(true))(Identity(false)),
88	///     Identity(false)
89	/// );
90	/// ```
91	fn apply_second<'a, ClonableFnBrand: 'a + ClonableFn, A: 'a + Clone, B: 'a + Clone>(
92		_fa: Apply0L1T<Self, A>
93	) -> ApplyClonableFn<'a, ClonableFnBrand, Apply0L1T<Self, B>, Apply0L1T<Self, B>> {
94		<ClonableFnBrand as ClonableFn>::new(identity)
95	}
96}
97
98impl Pointed for IdentityBrand {
99	/// # Examples
100	///
101	/// ```
102	/// use fp_library::{brands::{RcFnBrand, IdentityBrand}, functions::pure, types::Identity};
103	///
104	/// assert_eq!(
105	///     pure::<RcFnBrand, IdentityBrand, _>(()),
106	///     Identity(())
107	/// );
108	/// ```
109	fn pure<ClonableFnBrand: ClonableFn, A: Clone>(a: A) -> Apply0L1T<Self, A> {
110		Identity(a)
111	}
112}
113
114impl Semimonad for IdentityBrand {
115	/// # Examples
116	///
117	/// ```
118	/// use fp_library::{brands::{IdentityBrand, RcFnBrand}, functions::{bind, pure}, types::Identity};
119	/// use std::rc::Rc;
120	///
121	/// assert_eq!(
122	///     bind::<RcFnBrand, IdentityBrand, _, _>(Identity(()))(Rc::new(pure::<RcFnBrand, IdentityBrand, _>)),
123	///     Identity(())
124	/// );
125	/// ```
126	fn bind<'a, ClonableFnBrand: 'a + ClonableFn, A: 'a + Clone, B: Clone>(
127		ma: Apply0L1T<Self, A>
128	) -> ApplyClonableFn<
129		'a,
130		ClonableFnBrand,
131		ApplyClonableFn<'a, ClonableFnBrand, A, Apply0L1T<Self, B>>,
132		Apply0L1T<Self, B>,
133	> {
134		<ClonableFnBrand as ClonableFn>::new(
135			move |f: ApplyClonableFn<'a, ClonableFnBrand, _, _>| f(ma.to_owned().0),
136		)
137	}
138}
139
140impl Foldable for IdentityBrand {
141	/// # Examples
142	///
143	/// ```
144	/// use fp_library::{brands::{IdentityBrand, RcFnBrand}, functions::fold_right, types::Identity};
145	/// use std::rc::Rc;
146	///
147	/// assert_eq!(
148	///     fold_right::<RcFnBrand, IdentityBrand, i32, i32>(Rc::new(|x| Rc::new(move |y| x + y)))(0)(Identity(3)),
149	///     3
150	/// );
151	/// assert_eq!(
152	///     fold_right::<RcFnBrand, IdentityBrand, i32, i32>(Rc::new(|x| Rc::new(move |y| x * y)))(2)(Identity(4)),
153	///     8
154	/// );
155	/// ```
156	fn fold_right<'a, ClonableFnBrand: 'a + ClonableFn, A: Clone, B: Clone>(
157		f: ApplyClonableFn<'a, ClonableFnBrand, A, ApplyClonableFn<'a, ClonableFnBrand, B, B>>
158	) -> ApplyClonableFn<
159		'a,
160		ClonableFnBrand,
161		B,
162		ApplyClonableFn<'a, ClonableFnBrand, Apply0L1T<Self, A>, B>,
163	> {
164		<ClonableFnBrand as ClonableFn>::new(move |b: B| {
165			<ClonableFnBrand as ClonableFn>::new({
166				let f = f.clone();
167				move |fa: Apply0L1T<Self, _>| f(fa.0)(b.to_owned())
168			})
169		})
170	}
171}
172
173impl Traversable for IdentityBrand {
174	/// # Examples
175	///
176	/// ```
177	/// use fp_library::{brands::{IdentityBrand, OptionBrand, RcFnBrand}, functions::traverse, types::Identity};
178	/// use std::rc::Rc;
179	///
180	/// assert_eq!(
181	///     traverse::<RcFnBrand, IdentityBrand, OptionBrand, i32, i32>(Rc::new(|x| Some(x * 2)))(Identity(3)),
182	///     Some(Identity(6))
183	/// );
184	/// assert_eq!(
185	///     traverse::<RcFnBrand, IdentityBrand, OptionBrand, i32, i32>(Rc::new(|x| None))(Identity(3)),
186	///     None
187	/// );
188	/// ```
189	fn traverse<'a, ClonableFnBrand: 'a + ClonableFn, F: Applicative, A: Clone, B: 'a + Clone>(
190		f: ApplyClonableFn<'a, ClonableFnBrand, A, Apply0L1T<F, B>>
191	) -> ApplyClonableFn<'a, ClonableFnBrand, Apply0L1T<Self, A>, Apply0L1T<F, Apply0L1T<Self, B>>>
192	where
193		Apply0L1T<F, B>: Clone,
194		Apply0L1T<F, ApplyClonableFn<'a, ClonableFnBrand, Apply0L1T<Self, B>, Apply0L1T<Self, B>>>:
195			Clone,
196		Apply0L1T<Self, B>: 'a,
197		Apply0L1T<Self, Apply0L1T<F, B>>: 'a,
198	{
199		<ClonableFnBrand as ClonableFn>::new(move |ta: Apply0L1T<Self, _>| {
200			map::<ClonableFnBrand, F, B, _>(<ClonableFnBrand as ClonableFn>::new(
201				pure::<ClonableFnBrand, Self, _>,
202			))(f(ta.0))
203		})
204	}
205}