I'm trying to port this program that computes the nth derivative of x^x symbolically to Rust. It seems to be mostly easy:
use std::rc::Rc;
type Expr = Rc<Expr2>;
enum Expr2 {
Int(i32),
Var(String),
Add(Expr, Expr),
Mul(Expr, Expr),
Pow(Expr, Expr),
Ln(Expr),
}
use Expr2::*;
fn pown(a: i32, b: i32) -> i32 {
match b {
0 => 1,
1 => a,
n => {
let b = pown(a, b / 2);
let b2 = b * b;
if n % 2 == 0 {
b2
} else {
b2 * a
}
}
}
}
fn add(f: Expr, g: Expr) -> Expr {
match (f, g) {
(Int(m), Int(n)) => Int(m + n),
(Int(0), f) => f,
(f, Int(n)) => add(Int(n), f),
(f, Add(Int(n), g)) => add(Int(n), add(f, g)),
(Add(f, g), h) => add(f, add(g, h)),
(f, g) => Add(f, g),
}
}
fn mul(f: Expr, g: Expr) -> Expr {
match (f, g) {
(Int(m), Int(n)) => Int(m * n),
(Int(0), f) => Int(0),
(Int(1), f) => f,
(f, Int(n)) => mul(Int(n), f),
(f, Mul(Int(n), g)) => mul(Int(n), mul(f, g)),
(Mul(f, g), h) => mul(f, mul(g, h)),
(f, g) => Mul(f, g),
}
}
fn pow(f: Expr, g: Expr) -> Expr {
match (f, g) {
(Int(m), Int(n)) => Int(pown(m, n)),
(f, Int(0)) => Int(1),
(f, Int(1)) => f,
(Int(0), f) => Int(1),
(f, g) => Pow(f, g),
}
}
fn ln(f: Expr) -> Expr {
match f {
Int(1) => Int(0),
f => Ln(f),
}
}
fn d(x: String, f: Expr) -> Expr {
match f {
Int(_) => Int(0),
Var(y) => if x == y {
x
} else {
y
},
Add(f, g) => add(d(x, f), d(x, g)),
Mul(f, g) => add(mul(f, d(x, g)), mul(g, d(x, f))),
Pow(f, g) => mul(
pow(f, g),
add(mul(mul(g, d(x, f)), pow(f, Int(-1))), mul(ln(f), d(x, g))),
),
Ln(f) => mul(d(x, f), pow(f, Int(-1))),
}
}
fn count(f: Expr) -> i32 {
match f {
Int(_) | Var(_) => 1,
Add(f, g) | Mul(f, g) | Pow(f, g) => count(f) + count(g),
Ln(f) => count(f),
}
}
fn string_of_expr(f: Expr) -> String {
count(f).to_string();
}
fn nest(n: i32, f: Expr, x: Expr) -> Expr {
if n == 0 {
x
} else {
nest(n - 1, f, f(x))
}
}
fn deriv(f: Expr) -> Expr {
let df = d("x", f);
format!("D({}) = {}", string_of_expr(f), string_of_expr(df));
df
}
fn main() {
let x = "x";
let f = pow(x, x);
// FIXME: Read command-line argument
let df = nest(9, deriv, f);
format!("{}", count(df));
}
The type needs to be converted into a reference counted enum in Rust and pattern matching makes for very similar code except... it doesn't work. From what I can gather, patterns in Rust cannot match upon the result of dereferencing an Rc. So, no matter what I do, it fails on nested patterns like (f, Add(Int(n), g)).
Am I missing something or is it really impossible for nested patterns to match over recursive datatypes in Rust? Apparently there is something called "box syntax" to dereference inside a pattern (amongst other things) that has been on the drawing board for four years.
It appears that yes, it is currently impossible to do this. Recursive datatypes require indirection, e.g. Rc. Indirection requires dereferences when matching against nested patterns. There is no way to dereference inside a pattern match in Rust today.
The workaround is to compile your patterns by hand, i.e. as if you only had C-style switch.
A feature called "box patterns" has been discussed since 2014 that may solve this problem in the future but it hasn't shipped.
Related
I am trying to write a higher order function that compose two async function.
i am basically looking for the async version this
fn compose<A, B, C, G, F>(f: F, g: G) -> impl Fn(A) -> C
where
F: Fn(A) -> B,
G: Fn(B) -> C,
{
move |x| g(f(x))
}
This my attempt so far.
fn compose_future<A, B, C, G, F>(f: F, g: G) -> (impl Fn(A) -> impl Future<C>)
where
F: Fn(A) -> impl Future<B>,
G: Fn(B) -> impl Future<C>,
{
move |x| async { g(f(x).await).await }
}
and i get the following error
error[E0562]: `impl Trait` not allowed outside of function and inherent method return types
--> src\channel.rs:13:17
|
13 | F: Fn(A) -> impl Future<B>,
| ^^^^^^^^^^^^^^
Is it possible to accomplish this ?
I'm not sure it is possible to do it that simple with impl Trait-s. The one solution I can come up with is old-fashioned future types usage without async-await feature. TLDR: full playground. Async-await uses a generators which internally holds a state machine, so we need to define it manually:
enum State<In, F, FutOutF, G, FutOutG> {
Initial(In, F, G), // Out composed type created
FirstAwait(FutOutF, G), // Composed type waits for the first future
SecondAwait(FutOutG), // and for the second
// here can be a `Completed` state, but it simpler
// to handle it with `Option<..>` in our future itself
}
Then define a composed type itself:
struct Compose<In, Out, F, FutOutF, G, FutOutG> {
state: Option<State<In, F, FutOutF, G, FutOutG>>,
_t: PhantomData<Out>,
}
// And "entry-point" would be something like that:
fn compose_fut<In, Out, F, FutOutF, G, FutOutG>(
i: In,
f: F,
g: G,
) -> Compose<In, Out, F, FutOutF, G, FutOutG> {
Compose {
state: Some(State::Initial(i, f, g)),
_t: PhantomData,
}
}
Then comes the most complex part - impl Future itself, here a base impl declaration without implementation:
impl<In, Mid, Out, F, FutOutF, G, FutOutG> Future for Compose<In, Out, F, FutOutF, G, FutOutG>
where
FutOutF: Future<Output = Mid>,
F: FnOnce(In) -> FutOutF,
FutOutG: Future<Output = Out>,
G: FnOnce(Mid) -> FutOutG,
{
type Output = Out;
fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
// here comes the magic
}
}
Values transformed as following: In -> Mid -> Out, where F and G are our composed functions and their output are FutOutF and FutOutG accordingly. And finally Future::poll implementation:
let this = unsafe { self.get_unchecked_mut() };
let state = this.state.take();
match state {
None => Poll::Pending, // invalid state
Some(State::Initial(i, f, g)) => {
let fut = f(i);
this.state = Some(State::FirstAwait(fut, g));
cx.waker().wake_by_ref();
Poll::Pending
}
Some(State::FirstAwait(mut fut, g)) => {
let val = match unsafe { Pin::new_unchecked(&mut fut) }.poll(cx) {
Poll::Ready(v) => v,
Poll::Pending => {
this.state = Some(State::FirstAwait(fut, g));
return Poll::Pending;
}
};
let fut = g(val);
this.state = Some(State::SecondAwait(fut));
cx.waker().wake_by_ref();
Poll::Pending
}
Some(State::SecondAwait(mut fut)) => {
match unsafe { Pin::new_unchecked(&mut fut) }.poll(cx) {
Poll::Ready(v) => Poll::Ready(v),
Poll::Pending => {
this.state = Some(State::SecondAwait(fut));
Poll::Pending
}
}
}
}
I avoid any library to make it "plain", usually unsafe parts are handled with pin-project or futures::pin_mut. The state management is fairly complex, so I suggest to re-check the implementation, there might be mistakes.
There are two functions; funA and funB, respectively. a.i, a.o, ah, w, c are arrays in the function funA. The function funA shall be passed as a functional parameter to the function funB and the arrays should be able to be accessed by the function funB. Unfortunately, the syntax checker encountered an error "Error: Unbound record field a". Please comment, how to declare functional parameters in OCaml/ReasonML?
Full list
module Test = {
let vector = Array.init;
let matrix = (m, n, f) => vector(m, i => vector(n, f(i)));
let length = Array.length;
let rand = (x0, x1) => x0 +. Random.float(x1 -. x0);
let funA = (ni, nh, no) => {
let init = (fi, fo) => {
let i = matrix(ni + 1, nh, fi);
let o = matrix(nh, no, fo);
();
};
let a = {
let i = vector(ni + 1, _ => 1.0);
let o = vector(no, _ => 1.0);
();
};
let ah = vector(nh, _ => 1.0);
let w = init((_, _) => rand(-0.2, 0.4), (_, _) => rand(-2.0, 4.0));
let c = init((_, _) => 0.0, (_, _) => 0.0);
();
};
let funB = (net, inputs) => {
let (ni, nh, no) = (
length(net.a.i),
length(net.ah),
length(net.a.o),
);
();
};
};
To resolve the functional parameter funA which is inaccessible in the function funB, apply the following type at the beginning of the module.
module Test = {
type io('a) = {
i: 'a,
o: 'a,
};
type vec = array(float);
type mat = array(vec);
type funA = {
a: io(vec),
ah: vec,
w: io(mat),
c: io(mat),
};
.......
If I have a bunch of functions which strictly chain together, then it's easy enough to use compose to combine them:
f1 : A -> B
f2 : B -> C
f3 : C -> D
pipe(f1, f2, f3) : A -> D
Often I find that things aren't quite so perfect, and the information contained in A is needed again in a later stage:
f1 : A -> B
f2 : B -> C
f3 : (A, C) -> D
How do I elegantly compose these functions? I feel like I want some kind of "stash" to tuck the A into a Pair or something, map pipe(f1,f2) over the second element and then I have everything ready for f3. I can't come up with a very elegant way of doing this though, and it feels like a common enough situation that there must be an estalished pattern!
As an concrete example, say I have a string and I want to return it if it has an even length, otherwise I want to return none.
f1 = len
f2 = mod(2)
f3 = (s, m) => m == 0 ? Just(s) : None
How do I compose these together?
The type of function composition doesn't allow this. I think that a lambda along with currying is straightforward and more explicit than passing a tuple type through the composition:
const f1 = s => s.length;
const f2 = n => n % 2;
const f3 = s => m => m === 0 ? s : null;
const comp3 = f => g => h => x => f(g(h(x)));
const main = s => comp3(f3(s)) (f2) (f1) (s);
console.log(main("hallo"));
console.log(main("halloo"));
If you absolutely want it point free you can also utilize the fact that function composition may yield another function:
const f1 = s => s.length;
const f2 = n => n % 2;
const f3 = s => m => m === 0 ? s : null;
const comp3 = f => g => h => x => f(g(h(x)));
const join = f => x => f(x) (x); // monadic join
const flip = f => y => x => f(x) (y);
const main = join(comp3(flip(f3)) (f2) (f1));
console.log(main("hallo"));
console.log(main("halloo"));
Pretty hard to read though.
Just to elaborate a little on my comment on the original question - I have found a way of achieving what I want in quite a (IMO) nice style. It still feels like I'm reinventing the wheel though, so another way to rephrase the original question might be: do you recognise the function signatures below?
// stash :: A => [A,A]
const stash = x => [x, x];
// map :: (A => C) => [A,B] => [A,C]
const map = f => ([a, b]) => [a, f(b)];
// unstash :: ((A,B) => C) => [A,B] => C
const unstash = f => ([a, b]) => f(a, b);
const f1 = s => s.length;
const f2 = n => n % 2 === 0;
const f3 = (s, x) => x ? Option.some(s) : Option.none;
const getEvenName =
pipe(
stash,
map(f1),
map(f2),
unstash(f3)
);
getEvenName("Lucy") // Some("Lucy");
getEvenName("Tom") // None
I was looking through array extension functions and found reduce() one
inline fun <S, T: S> Array<out T>.reduce(operation: (acc: S, T) -> S): S {
if (isEmpty())
throw UnsupportedOperationException("Empty array can't be reduced.")
var accumulator: S = this[0]
for (index in 1..lastIndex) {
accumulator = operation(accumulator, this[index])
}
return accumulator
}
here the accumulator variable of type S assigned with first element from the array with type T.
Can't wrap my head around the real use case of reduce() function with two data types. Here synthetic example which actually doesn't make any sense.
open class A(var width: Int = 0)
class B(width: Int) : A(width)
val array = arrayOf(A(7), A(4), A(1), A(4), A(3))
val res = array.reduce { acc, s -> B(acc.width + s.width) }
Seems most real life use cases with this function use this signature:
inline fun <T> Array<out T>.reduce(operation: (acc: T, T) -> T): T
Can you help with providing some examples, where reduce() function can be useful with different types.
Here is an example:
interface Expr {
val value: Int
}
class Single(override val value: Int): Expr
class Sum(val a: Expr, val b: Expr): Expr {
override val value: Int
get() = a.value + b.value
}
fun main(args: Array<String>) {
val arr = arrayOf(Single(1), Single(2), Single(3));
val result = arr.reduce<Expr, Single> { a, b -> Sum(a, b) }
println(result.value)
}
I am trying to populate a vector with a sequence of values. In order to calculate the first value I need to calculate the second value, which depends on the third value etc etc.
let mut bxs = Vec::with_capacity(n);
for x in info {
let b = match bxs.last() {
Some(bx) => union(&bx, &x.bbox),
None => x.bbox.clone(),
};
bxs.push(b);
}
bxs.reverse();
Currently I just fill the vector front to back using v.push(x) and then reverse the vector using v.reverse(). Is there a way to do this in a single pass?
Is there a way to do this in a single pass?
If you don't mind adapting the vector, it's relatively easy.
struct RevVec<T> {
data: Vec<T>,
}
impl<T> RevVec<T> {
fn push_front(&mut self, t: T) { self.data.push(t); }
}
impl<T> Index<usize> for RevVec<T> {
type Output = T;
fn index(&self, index: usize) -> &T {
&self.data[self.len() - index - 1]
}
}
impl<T> IndexMut<usize> for RevVec<T> {
fn index_mut(&mut self, index: usize) -> &mut T {
let len = self.len();
&mut self.data[len - index - 1]
}
}
The solution using unsafe is below. The unsafe version is slightly more than 2x as fast as the safe version using reverse(). The idea is to use Vec::with_capacity(usize) to allocate the vector, then use ptr::write(dst: *mut T, src: T) to write the elements into the vector back to front. offset(self, count: isize) -> *const T is used to calculate the offset into the vector.
extern crate time;
use std::fmt::Debug;
use std::ptr;
use time::PreciseTime;
fn scanl<T, F>(u : &Vec<T>, f : F) -> Vec<T>
where T : Clone,
F : Fn(&T, &T) -> T {
let mut v = Vec::with_capacity(u.len());
for x in u.iter().rev() {
let b = match v.last() {
None => (*x).clone(),
Some(y) => f(x, &y),
};
v.push(b);
}
v.reverse();
return v;
}
fn unsafe_scanl<T, F>(u : &Vec<T> , f : F) -> Vec<T>
where T : Clone + Debug,
F : Fn(&T, &T) -> T {
unsafe {
let mut v : Vec<T> = Vec::with_capacity(u.len());
let cap = v.capacity();
let p = v.as_mut_ptr();
match u.last() {
None => return v,
Some(x) => ptr::write(p.offset((u.len()-1) as isize), x.clone()),
};
for i in (0..u.len()-1).rev() {
ptr::write(p.offset(i as isize), f(v.get_unchecked(i+1), u.get_unchecked(i)));
}
Vec::set_len(&mut v, cap);
return v;
}
}
pub fn bench_scanl() {
let lo : u64 = 0;
let hi : u64 = 1000000;
let v : Vec<u64> = (lo..hi).collect();
let start = PreciseTime::now();
let u = scanl(&v, |x, y| x + y);
let end= PreciseTime::now();
println!("{:?}\n in {}", u.len(), start.to(end));
let start2 = PreciseTime::now();
let u = unsafe_scanl(&v, |x, y| x + y);
let end2 = PreciseTime::now();
println!("2){:?}\n in {}", u.len(), start2.to(end2));
}