I have a call to env::vars_os and would like to print all of them in a functional manner:
env::vars_os()
.map(|(k, v)| println!("k : {:?}, v : {:?} \n", k, v));
This prints nothing, but the article Destructuring and Pattern Matching indicates this should be possible.
Looking at the documentation for vars_os(), we see that it is an iterator over tuples, which have the syntax (a, b). So, changing your code to
env::vars_os()
.map(|(k, v)| println!("k : {:?}, v : {:?} \n", k, v));
should do the trick.
The syntax you are using would destructure into a struct, only you left out the struct's name, which would precede the curly braces.
Iterators in Rust are lazily evaluated, which means none of the code in the map is executed until the iterator is consumed. You can do this by calling collect(). However, the idiomatic way to do it would be to put code that has side-effects (such as printing) in a for loop instead of a map:
for (k, v) in env::vars_os() {
println!("k : {:?}, v : {:?} \n", k, v);
}
Related
I have a function with following declaration:
fn find_solutions_internal<'a, I>(&self, words: I, iterate_from: usize, chain: &mut Vec<u32>)
where I: Iterator<Item=&'a u32> + Clone;
Because the function recursively iterates over the same vector (max-depth of recursion is 5) with different filters I decided that it would be more effecient to pass the iterator as an argument.
Following part of code causes error:
let iterator = words.skip(iterate_from).filter(|&mask| mask & last_mask == 0);
let filtered_words = iterator.clone();
iterator.enumerate().for_each(|(i, &mask)| {
chain.push(mask);
self.find_solutions_internal(filtered_words.clone(), i, chain); // filtered_words.clone() is what indirectly causes the error
chain.pop();
});
The error:
error: reached the recursion limit while instantiating `<std::iter::Filter<std::iter::Sk...]>::{closure#0}]>::{closure#0}]>`
115 | self.iter.fold(init, fold)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: `<std::iter::Filter<I, P> as Iterator>::fold` defined here
...
Self-contained example of the problematic code: https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=ada8578f166ad2a34373d82cc376921f
Working example with collected iteration to vector: https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=4c13d2d0ac17038dac61c9e2d59bbab5
As #Jmb commented, the compiler does not try figuring out how many times the function recurses, at least not for the purpose of allowing this kind of code to compile. The compiler assumes each call to find_solutions_internal() can potentially recurse, and so the compiler gets stuck repeatedly instantiating the function, as each recursive call has a unique iterator parameter type.
We can fix this problem by passing the iterator as a trait object when making the recursive call, though the fact that we're cloning the iterator complicates things, as the Clone trait doesn't work with trait objects. We can work around that with the dyn_clone crate, at the cost of some boilerplate.
First we define a clonable iterator trait:
use dyn_clone::DynClone;
trait ClonableIterator<T>: Iterator<Item = T> + DynClone {}
impl<I, T> ClonableIterator<T> for I where I: Iterator<Item = T> + DynClone {}
dyn_clone::clone_trait_object!(<T> ClonableIterator<T>);
Then in the recursive call we construct the trait object:
self.find_solutions_internal(
Box::new(filtered_words.clone()) as Box<dyn ClonableIterator<_>>,
i,
chain,
);
While the above solution works, I think it'll likely end up slower than doing the simple thing of just collecting into a Vec. If the vector is really big, using a datastructure like Vector from the im crate, which supports O(1) cloning and O(log n) remove might be faster.
I came across this while doing the 2018 Advent of Code (Day 2, Part 1) solution in Rust.
The problem to solve:
Take the count of strings that have exactly two of the same letter, multiplied by the count of strings that have exactly three of the same letter.
INPUT
abcdega
hihklmh
abqasbb
aaaabcd
The first string abcdega has a repeated twice.
The second string hihklmh has h repeated three times.
The third string abqasbb has a repeated twice, and b repeated three times, so it counts for both.
The fourth string aaaabcd contains a letter repeated 4 times (not 2, or 3) so it does not count.
So the result should be:
2 strings that contained a double letter (first and third) multiplied by 2 strings that contained a triple letter (second and third) = 4
The Question:
const PUZZLE_INPUT: &str =
"
abcdega
hihklmh
abqasbb
aaaabcd
";
fn letter_counts(id: &str) -> [u8;26] {
id.chars().map(|c| c as u8).fold([0;26], |mut counts, c| {
counts[usize::from(c - b'a')] += 1;
counts
})
}
fn has_repeated_letter(n: u8, letter_counts: &[u8;26]) -> bool {
letter_counts.iter().any(|&count| count == n)
}
fn main() {
let ids_iter = PUZZLE_INPUT.lines().map(letter_counts);
let num_ids_with_double = ids_iter.clone().filter(|id| has_repeated_letter(2, id)).count();
let num_ids_with_triple = ids_iter.filter(|id| has_repeated_letter(3, id)).count();
println!("{}", num_ids_with_double * num_ids_with_triple);
}
Rust Playground
Consider line 21. The function letter_counts takes only one argument, so I can use the syntax: .map(letter_counts) on elements that match the type of the expected argument. This is really nice to me! I love that I don't have to create a closure: .map(|id| letter_counts(id)). I find both to be readable, but the former version without the closure is much cleaner to me.
Now consider lines 22 and 23. Here, I have to use the syntax: .filter(|id| has_repeated_letter(3, id)) because the has_repeated_letter function takes two arguments. I would really like to do .filter(has_repeated_letter(3)) instead.
Sure, I could make the function take a tuple instead, map to a tuple and consume only a single argument... but that seems like a terrible solution. I'd rather just create the closure.
Leaving out the only argument is something that Rust lets you do. Why would it be any harder for the compiler to let you leave out the last argument, provided that it has all of the other n-1 arguments for a function that takes n arguments.
I feel like this would make the syntax a lot cleaner, and it would fit in a lot better with the idiomatic functional style that Rust prefers.
I am certainly no expert in compilers, but implementing this behavior seems like it would be straightforward. If my thinking is incorrect, I would love to know more about why that is so.
No, you cannot pass a function with multiple arguments as an implicit closure.
In certain cases, you can choose to use currying to reduce the arity of a function. For example, here we reduce the add function from 2 arguments to one:
fn add(a: i32, b: i32) -> i32 {
a + b
}
fn curry<A1, A2, R>(f: impl FnOnce(A1, A2) -> R, a1: A1) -> impl FnOnce(A2) -> R {
move |a2| f(a1, a2)
}
fn main() {
let a = Some(1);
a.map(curry(add, 2));
}
However, I agree with the comments that this isn't a benefit:
It's not any less typing:
a.map(curry(add, 2));
a.map(|v| add(v, 2));
The curry function is extremely limited: it chooses to use FnOnce, but Fn and FnMut also have use cases. It only applies to a function with two arguments.
However, I have used this higher-order function trick in other projects, where the amount of code that is added is much greater.
I'm not too familiar with OCaml's model of evaluation. I'd be grateful if someone could explain why these two lines of code give different results:
List.iter (fun s -> Printf.printf "%s" s) ["a"; "b"; "c"];; (* prints abc *)
List.iter (fun f -> f) [Printf.printf "a"; Printf.printf "b"; Printf.printf "c"];; (* prints cba *)
OCaml is a strict functional programming language: a function's arguments are evaluated as values (and side-effects in the expressions happen) before they are passed to the function (and any side-effects inside the function can happen).
In order to understand your second example, it is best to desugar it a bit:
List.cons
(Printf.printf "a")
(List.cons (Printf.printf "b") (List.cons (Printf.printf "c") []))
When a function is passed several arguments at once—as is the case for all List.cons functions here—the order of evaluation of the arguments is unspecified. This order can differ between the bytecode and the native compiler, for instance. Here, the compiler you used decided to evaluate the first List.cons's second argument first. In doing this, it encountered an application (the second List.cons)
…
In evaluating the arguments of the last List.cons, it printed c. The result was (), which allowed it to build the value [()]. This argument being ready, it now evaluated the other argument of the second List.cons. That made it print b. Finally, since the argument [();()] of the first List.cons was ready, it evaluated the other argument. That made it print a.
As Pascal Cuoq already answered your question, let me just clear up a potential misunderstanding that I take from the question title: Nowhere in your code is a list of functions.
In the first line there is a list of strings, ["a";"b";"c"].
In the second line you have a list with elements such as Printf.printf "a", which are function applications. Their resulting type is unit, also not a function type. (In fact the list is just [();();()].)
An example of a list of funtions would be
[(fun () -> print_string "a"); (fun () -> print_string "b"); (fun () -> ())]
In general, I prefer to write initializer functions with descriptive names. However, for some structs, there is an obvious default initializer function. The standard Rust name for such a function is new, placed in the impl block for the struct. However, today I realized that I can give a function the same name as a struct, and thought this would be a good way to implement the obvious initializer function. For example:
#[derive(Debug, Clone, Copy)]
struct Pair<T, U> {
first: T,
second: U,
}
#[allow(non_snake_case)]
fn Pair<T, U>(first: T, second: U) -> Pair<T, U> {
Pair::<T, U> {
first: first,
second: second,
}
}
fn main(){
let x = Pair(1, 2);
println!("{:?}", x);
}
This is, in my opinion, much more appealing than this:
let x = Pair::new(1, 2);
However, I've never seen anyone else do this, and my question is simply if there are any problems with this approach. Are there, for example, ambiguities which it can cause which will not be there with the new implementation?
If you want to use Pair(T, U) then you should consider using a tuple struct instead:
#[derive(Debug, Clone, Copy)]
struct Pair<T, U>(T, U);
fn main(){
let x = Pair(1, 2);
println!("{:?}", x);
println!("{:?}, {:?}", (x.0, x.1));
}
Or, y’know, just a tuple ((T, U)). But I presume that Pair is not your actual use case.
There was a time when having identically named functions was the convention for default constructors; this convention fell out of favour as time went by. It is considered bad form nowadays, probably mostly for consistency. If you have a tuple struct (or variant) Pair(T, U), then you can use Pair(first, last) in a pattern, but if you have Pair { first: T, last: U } then you would need to use something more like Pair { first, last } in a pattern, and so your Pair(first, last) function would be inconsistent with the pattern. It is generally felt, thus, that these type of camel-case functions should be reserved solely for tuple structs and tuple variants, where it can be known that it is genuinely reflecting what is contained in the data structure with no further processing or magic.
I want to write a function that will take an arbitrary number of (curried) arguments and simply print them out (or perform some other unspecified action with them). Here is what I have come up with:
let print arg =
let rec print args arg =
if not (FSharpType.IsFunction(typeof<'t>)) then
printfn "%A" args
Unchecked.defaultof<'t>
else
print (box arg::args)
print []
When I try to compile this I get the error The resulting type would be infinite when unifying ''t' and ''a -> 't.
I know I could just pass the arguments as a list, but I am trying to develop an API of sorts where this would be a useful idiom to have.
Is there some clever compiler trick to make such a function possible in F# or is it a lost cause?
It seems that the two branches of the inner print want to return different types: the "then" part wants to return 't, but the "else" part wants to return 'a -> 't, where 't is necessarily the same in both branches. That is, your function tries to return either its own return type or a function from another type to its own return type. Such combined return type would, indeed, be infinite, which is in perfect accordance with what you set out to do - namely, create a function with infinite number of arguments. Though I do not know how to formally prove it, I would say this is indeed impossible.
If your goal is to simply create a list of boxed values, you could get away with defining a few infix operators.
let (<+>) a b = a # [(box b)]
let (<&>) a b = [(box a); (box b)]
let xs = 5 <&> "abc" <+> 3.0 <+> None <+> true
>> val xs : obj list = [5; "abc"; 3.0; null; true]
Alternatively, with carefully chosen operator precedence, you can apply a function (but then you'll need a terminator):
let (^>) a b = (box a)::b
let (<&>) f xs = f xs
let print xs = sprintf "%A" xs
let xs = print <&> 5 ^> "abc" ^> 3.0 ^> None ^> true ^> []
>> val xs : string = "[5; "abc"; 3.0; null; true]"