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::ApplyFn,
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: ApplyFn<'a, ClonableFnBrand, A, B>
36	) -> ApplyFn<'a, ClonableFnBrand, Apply0L1T<Self, A>, Apply0L1T<Self, B>> {
37		ClonableFnBrand::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, ApplyFn<'a, ClonableFnBrand, A, B>>
55	) -> ApplyFn<'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	) -> ApplyFn<'a, ClonableFnBrand, Apply0L1T<Self, B>, Apply0L1T<Self, A>> {
75		ClonableFnBrand::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	) -> ApplyFn<'a, ClonableFnBrand, Apply0L1T<Self, B>, Apply0L1T<Self, B>> {
94		ClonableFnBrand::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	) -> ApplyFn<
129		'a,
130		ClonableFnBrand,
131		ApplyFn<'a, ClonableFnBrand, A, Apply0L1T<Self, B>>,
132		Apply0L1T<Self, B>,
133	> {
134		ClonableFnBrand::new(move |f: ApplyFn<'a, ClonableFnBrand, _, _>| f(ma.to_owned().0))
135	}
136}
137
138impl Foldable for IdentityBrand {
139	/// # Examples
140	///
141	/// ```
142	/// use fp_library::{brands::{IdentityBrand, RcFnBrand}, functions::fold_right, types::Identity};
143	/// use std::rc::Rc;
144	///
145	/// assert_eq!(
146	///     fold_right::<RcFnBrand, IdentityBrand, i32, i32>(Rc::new(|x| Rc::new(move |y| x + y)))(0)(Identity(3)),
147	///     3
148	/// );
149	/// assert_eq!(
150	///     fold_right::<RcFnBrand, IdentityBrand, i32, i32>(Rc::new(|x| Rc::new(move |y| x * y)))(2)(Identity(4)),
151	///     8
152	/// );
153	/// ```
154	fn fold_right<'a, ClonableFnBrand: 'a + ClonableFn, A: Clone, B: Clone>(
155		f: ApplyFn<'a, ClonableFnBrand, A, ApplyFn<'a, ClonableFnBrand, B, B>>
156	) -> ApplyFn<'a, ClonableFnBrand, B, ApplyFn<'a, ClonableFnBrand, Apply0L1T<Self, A>, B>> {
157		ClonableFnBrand::new(move |b: B| {
158			ClonableFnBrand::new({
159				let f = f.clone();
160				move |fa: Apply0L1T<Self, _>| f(fa.0)(b.to_owned())
161			})
162		})
163	}
164}
165
166impl Traversable for IdentityBrand {
167	/// # Examples
168	///
169	/// ```
170	/// use fp_library::{brands::{IdentityBrand, OptionBrand, RcFnBrand}, functions::traverse, types::Identity};
171	/// use std::rc::Rc;
172	///
173	/// assert_eq!(
174	///     traverse::<RcFnBrand, IdentityBrand, OptionBrand, i32, i32>(Rc::new(|x| Some(x * 2)))(Identity(3)),
175	///     Some(Identity(6))
176	/// );
177	/// assert_eq!(
178	///     traverse::<RcFnBrand, IdentityBrand, OptionBrand, i32, i32>(Rc::new(|x| None))(Identity(3)),
179	///     None
180	/// );
181	/// ```
182	fn traverse<'a, ClonableFnBrand: 'a + ClonableFn, F: Applicative, A: Clone, B: 'a + Clone>(
183		f: ApplyFn<'a, ClonableFnBrand, A, Apply0L1T<F, B>>
184	) -> ApplyFn<'a, ClonableFnBrand, Apply0L1T<Self, A>, Apply0L1T<F, Apply0L1T<Self, B>>>
185	where
186		Apply0L1T<F, B>: Clone,
187		Apply0L1T<F, ApplyFn<'a, ClonableFnBrand, Apply0L1T<Self, B>, Apply0L1T<Self, B>>>: Clone,
188		Apply0L1T<Self, B>: 'a,
189		Apply0L1T<Self, Apply0L1T<F, B>>: 'a,
190	{
191		ClonableFnBrand::new(move |ta: Apply0L1T<Self, _>| {
192			map::<ClonableFnBrand, F, B, _>(ClonableFnBrand::new(pure::<ClonableFnBrand, Self, _>))(
193				f(ta.0),
194			)
195		})
196	}
197}