Problem with "frunk map()" and generic type

The following iteration (with homogeneous types) works:

use frunk::*;                                                                                                             
use frunk_core::*;                                                                                                        
                                                                                                                          
struct A {                                                                                                                
    a: i8,                                                                                                                
}                                                                                                                         
                                                                                                                          
fn main() {                                                                                                               
    let data = hlist![A{a:1}, A{a:2}];                                                                                    
    let _ = data.map(                                                                                                     
        |x: A| println!("{}", x.a)                                                                                        
    );                                                                                                                    
}                                                                                                                         

However, the following one (with heterogeneous types) obviously doesn't:

use frunk::*;                                                                                                             
use frunk_core::*;                                                                                                        
                                                                                                                          
struct A<T> {                                                                                                             
    a: T,                                                                                                                 
}                                                                                                                         
                                                                                                                          
fn main() {                                                                                                               
    let data = hlist![A::<i8>{a:1}, A::<f64>{a:2.0}];                                                                     
    let _ = data.map(                                                                                                     
        |x: A| println!("{}", x.a)                                                                                        
    );                                                                                                                    
}                                                                                                                         

How can I make this work for the closure arg being a generic type? Thanks.

You'll need to implement Func and stuff that type in a Poly to pass it in to map.

struct MyFunc;

impl Func<???> for MyFunc { ... }

list.map(Poly(MyFunc));
1 Like

Thanks. I've come this far but I still can't figure it out -- also think I may make things too complicated. This is what I've got so far:


//# frunk = "*"
//# frunk_core = "*"

use frunk::{*, traits::Poly, traits::Func};

struct A<T> {
    a: T,
}

trait B<T> {
    fn new() -> A<T>;
}

impl B<i8> for A<i8> {
    fn new() -> A<i8> { A::<i8>{a: 1} }
}

impl B<f64> for A<f64> {
    fn new() -> A<f64> { A::<f64>{a: 2.0} }
}

impl A<i8> {
    pub fn create() -> Poly<A<i8>> {
        Poly(A::<i8>())
    }
}
impl Func<i8> for A::<i8> {
    type Output = i8;
    fn call(n: <A<i8> as B>::new) {n()}
}

impl A<f64> {
    pub fn create() -> Poly<A<f64>> {
        Poly(A::<f64>())
    }
}
impl Func<f64> for A::<f64> {
    type Output = f64;
    fn call(n: <A<f64> as B>::new) {n()}
}


fn main() {

    let data = hlist![A::<i8>::new, A::<f64>::new];
    let y = data.map(create);
    println!("list: {}", y);
}

Further help is much appreciated.

You can't have any stateful closures using Poly

struct A;

impl Func<i8> for A {
    type Output = i16;
    fn call(n: i8) {
        i16::from(n) + 1
    }
}

impl Func<f64> for A {
    type Output = f64;
    fn call(n: f64) {
        n*2.0
    }
}

let mapped = hlist![3_i8, 20.0_f64]
    .map(Poly(A));
assert_eq!(mapped, hlist![4_i16, 40.0_f64]);

Notice how I implemented Func on twice on the same type, only changing the input and output types.

OK, got it now for struct arguments; thanks. But what about having a function ref as arg:

//# frunk = "*"
//# frunk_core = "*"
/// with multiple arguments, last of which a function

use frunk::*;

struct A;

fn a() -> f64 { 20.0_f64 }
fn b() -> i16 { 1_i16 }

impl Func<(i8, fn() -> f64)> for A {
    type Output = f64;
    fn call(n: (i8, fn() -> f64)) -> Self::Output {
        (n.0 as f64) + n.1()
    }
}

impl Func<(i8, fn() -> i16)> for A {
    type Output = i16;
    fn call(n: (i8, fn() -> i16)) -> Self::Output {
        (n.0 as i16) + n.1()
    }
}

fn main() {

    let mapped = hlist![
       (3_i8, a),
       (2_i8, b)
       ]
        .map(Poly(A));
    assert_eq!(mapped, hlist![23_f64, 3_i16]);
    println!("{:?}", mapped);

}

This gives me:

...
map(Poly(A));
^^^ the trait `frunk_core::hlist::HMappable<frunk_core::traits::Poly<A>>` 
is not implemented for `frunk_core::hlist::HCons<(i8, fn() -> f64 {a}), 
frunk_core::hlist::HCons<(i8, fn() -> i16 {b}), frunk_core::hlist::HNil>>`

Thinking about it.... I can move the a() and b() calls from being args into their respective trait implementations....; it is less general though. However, this would work were it not for the fact that I then end up with two conflicting trait implementations for ...

Any suggestions? Thanks.

You'll need to cast the function items to function pointers.

fn foo(){}

// zero-sized function item that only refers to foo
let function_item = foo;

// pointer-sized function pointer that could refer to
// any function with the signature fn()
let function_pointer = foo as fn();

That's it! Thanks a lot!

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.