How to define an array of functions of different signature in F# - arrays

I would like to be able to use an array of functions along this line:
type SomeFunc =
| StringFunc of (int -> string)
| DecimalFunc of (int -> decimal)
let dataCols = Dict<string, SomeFunc>()
dataCols["A"] <- fun x -> sprintf "%d" x
dataCols["B"] <- fun x -> decimal x
// would want to have:
(dataCols["A"] 0) // "0"
(dataCols["B"] 0) // 0M
How could I express this idea in valid F# code?

The first thing is that you'll need to wrap the functions in StringFunc or DecimalFunc when putting them into the dictionary:
let dataCols = Dictionary<string, SomeFunc>()
dataCols["A"] <- StringFunc(fun x -> sprintf "%d" x)
dataCols["B"] <- DecimalFunc(fun x -> decimal x)
When you want to call the function, you'll need to handle the two cases separately. One issue here is that your two functions return different results. You cannot really do this directly, so when calling the function you'll have to return a boxed obj, or you'd have to define a new discriminated union that's either string or decimal. The first option looks like this:
let call func arg =
match func with
| StringFunc f -> box (f arg)
| DecimalFunc f -> box (f arg)
Then you can use the call helper:
call (dataCols["A"]) 0
call (dataCols["B"]) 0
The boxing means that you'll get back obj, but it's hard to say what would be the best way to handle this without knowing more about your specific situation.

From your code, I get the impression that the input type is always going to be the same (int in the example), in order to be able to call any column without knowing its type.
If so, you might want to use a DU for the return type, and not for the function type. This way you'll get the calling behaviour you want.
type ColumnValue =
| StringValue of string
| DecimalValue of decimal
let dataCols = Dictionary<string, (int -> ColumnValue)>()
dataCols.["A"] <- fun x -> StringValue (sprintf "%d" x)
dataCols.["B"] <- fun x -> DecimalValue (decimal x)
// what you get
dataCols.["A"] 0 // (StringValue "0")
match (dataCols.["A"] 0) with
| StringValue s -> printf "%s" s
| DecimalValue d -> printf "%M" d

Related

How to delete values from an unsigned integer array in rust

I am trying to write a function that removes all occurrences of 1,2 and 3 from an array of unsigned integers. I have used the retain method but the error I am getting is:
rustc -o main main.rs
error[E0599]: no method named `retain` found for array `[u32; 7]` in the current scope
--> main.rs:3:5
|
3 | arr.retain(|&x| x != 1 || x != 2 || x != 3);
| ^^^^^^ method not found in `[u32; 7]`
error: aborting due to previous error
For more information about this error, try `rustc --explain E0599`.
compiler exit status 1
This is what I have so far:
fn remover(arr:[u32;7]){
arr.retain(|&x| x != 1 || x != 2 || x != 3);
println!("{:?}",arr);
}
fn main() {
let v = [1,2,3,4,5,6,7];
remover(v);
}
Why can I not use the retain method? Is there something else I can use?
An array has a fixed size ([u32; 7] will always have 7 elements), therefore it doesn't make sense to remove elements from it.
If you want a dynamically sized sequence, you should use Vec, which does have a retain method.
Or you could keep an array and use Iterator::filter, if you don't actually need to update the source.
Arrays are statically sized in Rust, its size is part of the type. [u32; 7] defines the array to hold exactly 7 u32 values.
If you want to have a dynamic number of values, you will need to use Vec<u32> instead, i.e. declare v as vec![1,2,3,4,5,6,7] and make your remover() take Vec<u32> instead.
An alternative solution, you can proceed to filter to a slice of your array. By doing you do not duplicate data, avoiding creating a new vector.
fn main()
{
let v = [1,2,3,4,5,6,7];
let v_filtered = &v
.iter()
.filter(|&&x| x != 1 && x != 2 && x != 3)
.inspect(|&&x| println!("retained {}", x))
.collect::<Vec<_>>();
dbg!(v);
dbg!(v_filtered);
}
Pay attention, I changed the predicate of my filter.
Here is my playground
You can remove debugging info and iteration inspection value for the release version.

F# why arrays are not scrambled in a different way when mapping a function to scramble each array in an array

I wrote a function to scramble an array and map an array of arrays to scramble each one different but they are scrambled the same way
let rand = System.Random()
let shuffle (rand : System.Random)(array :int[] ) = let rng = new Random()
let mutable n = array.Length
while (n > 1) do
let k = rng.Next(n)
n <- n - 1
let temp = array.[n]
array.[n] <- array.[k]
array.[k] <- temp
array
let playsarray = shuffle rand
let scrambledarray = Array.map (fun x -> playsarray x )
let playsarra = fun (array : int[]) -> array |> playsarray
let smallarray = [1..10].ToArray()
let megaarray = Array.create 10 smallarray
let megarrayscrambled = megaarray |> scrambledarray
megarrayscrambled |> Seq.iter (fun y -> printfn "Ar: %A" y)
after running the code all the 10 arrays have the same order in the data ej
Ar: [|5; 1; 7; 2; 8; 10; 6; 3; 9; 4|]
Ar: [|5; 1; 7; 2; 8; 10; 6; 3; 9; 4|] and so on ...
There are two problems with your code.
First, your shuffle function takes a rand parameter but isn't actually using it: inside the function you create a new System.Random instance and use it instead of using the one passed in. The docs for the System.Random constructor mention (in the examples) that the default constructor uses the current time as a seed, so if two Random objects are created in quick succession, they would have the same seed and thus produce the same values. To fix this problem, you just need to stop creating a new Random instance in your shuffle function and instead use the one passed in (I renamed it from rand to rng so that the rest of your code wouldn't need changing). Here's your shuffle function with that change made (and with much easier-to-read indentation: you don't have to start the first line of the function on the same line as the = sign; you can put it on the next line and just indent one indentation level, four spaces):
let shuffle (rng : System.Random) (array : int[]) =
let mutable n = array.Length // The number of items left to shuffle (loop invariant).
while (n > 1) do
let k = rng.Next(n) // 0 <= k < n.
n <- n - 1 // n is now the last pertinent index;
let temp = array.[n] // swap array[n] with array[k] (does nothing if k == n).
array.[n] <- array.[k]
array.[k] <- temp
array
BUT that won't solve your issues just yet, because you've also misunderstood how Array.create works. It creates an array of a given size, where each item in the array contains the value you passed in. I.e., every entry in your megarrayscrambled array contains a reference to the same smallarray. If you did megarrayscrambled.[0].[0] <- 999 you'd see that this changed every one of the ten entries in megarrayscrambled, because they're the same array.
What you actually wanted was to use Array.init, not Array.create. Array.init takes a function and runs that function once per item it's creating in the array you're building. This means that if that function returns [1..10].ToArray(), then each time it's called it will return a different array, and you'll therefore get the results you expect. (By the way, you can create an array more simply by doing [|1..10|], and that's what I'll use in the sample code below).
So just change your let megaarray line to:
let megaarray = Array.init 10 (fun _ -> [|1..10|])
and then you should see the results you were expecting.
BTW, one more little detail: in one line you have Array.map (fun x -> playsarray x), but that is just equivalent to Array.map playsarray, which is a little simpler to read.

Understanding bind function

In this article, the author explains monad using this example (I am guessing Haskell is used):
bind f' :: (Float,String) -> (Float,String)
which implies that
bind :: (Float -> (Float,String)) -> ((Float,String) ->
(Float,String))
and proceed to ask to implement the function bind and offer the solution as:
bind f' (gx,gs) = let (fx,fs) = f' gx in (fx,gs++fs)
I am having problem understanding the solution. What would this look like in C or Swift?
I have gone as far as I can implementing the example and I am stuck at implementing bind:
let f: Float -> Float = { value in return 2 * value }
let g: Float -> Float = { value in return 10 + value }
let ff: Float -> (Float, String) = { value in return (f(value), "f called") }
let gg: Float -> (Float, String) = { value in return (g(value), "f called") }
In C++ I think it would look something like this:
#include <functional>
#include <string>
#include <utility>
using P = std::pair<float, std::string>;
using FP = std::function<P(P)>;
FP mbind(std::function<P(float)> f) {
return [f](P in) {
auto && res = f(in.first);
return {res.first, in.second + res.second};
};
}
In C you could do something similar by storing function pointers, though the invocation syntax would have to be more verbose since you'll need to pass the state around explicitly.
In Swift, perhaps something like this:
let bind: (Float -> (Float, String)) -> ((Float, String) -> (Float, String)) = {
lhs in
return {
rhs in
let result = lhs(rhs.0)
return (result.0, "\(result.1); \(rhs.1)" )
}
}
It is a bind for Writer monad. The bind function for that monad should do 2 things:
Execute computation with Float value.
Update the existing log (a String value).
Initially you have a tuple (oldFloat,oldString) and want to apply to this tuple a function with type Float -> (Float,String).
Your function takes an oldFloat value from tuple (oldFloat,oldString) and returns a tuple (newFloat,newString).
What behavior do you expect from your bind function? I suppose you want to get a tuple containing a newFloat and updated log oldString ++ new string, right? Here is a straitforward implementation of it:
bind f (oldFloat,oldString) =
-- apply function f to oldFloat from tuple (oldFloat,oldString)
-- to get a new tuple (newFloat,newString)
let (newFloat,newString) = f oldFloat
-- you want from your bind function to get a tuple containing
-- a newFloat and a newString added to oldString
in (newFloat, oldString ++ newString)

Error SML NJ-Operator and Operand don't agree

When I try to compile my ML Program ,I get an error saying:"Operator and Operand don't agree".
candidates.sml:78.8-78.40 Error: operator and operand don't agree [tycon mismatch]
operator domain: int * (int * 'Z * 'Y) list
operand: int * (int * real) list
in expression:
tr (n,candidates)
I understand the error but I can't find a solution.
The part of the code where I get the error is:
fun agonas fileName =
let
fun tr(n,[])=[]
| tr(n,((a,b,c)::d))=((n-a+1),b,c)::(tr(n,d))
val (n,l,candidates) = parse fileName
val cand = tr(n,candidates)
in
my_solution(l,cand)
end;
,where the candidates are related with the part below:
fun parse file =
let
(* a function to read an integer from an input stream *)
fun next_int input =
Option.valOf (TextIO.scanStream (Int.scan StringCvt.DEC) input)
(* a function to read a real that spans till the end of line *)
fun next_real input =
Option.valOf (TextIO.inputLine input)
(* open input file and read the two integers in the first line *)
val stream = TextIO.openIn file
val n = next_int stream
val l = next_int stream
val _ = TextIO.inputLine stream
(* a function to read the pair of integer & real in subsequent lines *)
fun scanner 0 acc = acc
| scanner i acc =
let
val d = next_int stream
val (SOME v) = Real.fromString (next_real stream)
in
scanner (i - 1) ((d, v) :: acc)
end
in
(n, l, rev(scanner n []))
end;
fun my_solution ( n , l ,candidates ) = [2 ,3 ,5 ,4 ,6]
fun agonas fileName = my_solution ( parse fileName )
I would appreciate it if you could find the mistake.Thanks in advance.
The problem is that parse, using scanner, builds a list of pairs — (int * real) list — while tr expects to get a list of triples — (int * 'Z * 'Y) list.
Not knowing what tr is supposed to do, the quick and dirty fix would be to change
tr(n,((a,b,c)::d))=((n-a+1),b,c)::(tr(n,d))
into
tr(n,((a,b)::d))=((n-a+1),b)::(tr(n,d))
But that may be the wrong solution - it depends on what the code is supposed to do.
(Sometimes it helps to explicitly write out the types yourself - even before writing the code - instead of relying on type inference to catch the places where you need to do some more thinking.)
The error message says it all: the offending line calls trans, and that is a function that expects two arguments, the second being a list of triples. However, you are passing it a list of pairs instead (as produced by your scanner function).
You didn't show us the trans function, so I cannot be more specific about what the appropriate fix would be.

Standard ML programming, array function

In ML I have an array of chars! I am trying to find an array function in order to give the function the char #"T" and returns me the position of this element in array. I tried the find function and it doesn't work like that!
findi from the Array structure will do what you want. For an array of type 'a array, findi takes a (int * 'a) -> bool and a 'a array and returns an (int * 'a) option. So if you want to take a character and just return the character's position, you just need figure out the appropriate arguments to pass to findi and the appropriate way to interpret the result.
So for instance:
- fun findPos char = (Option.map (fn (i,_) => i)) o (Array.findi (fn (_,c) => c = char));
stdIn:2.65 Warning: calling polyEqual
val findPos = fn : ''a -> ''a array -> int option
- findPos #"c" (Array.fromList (explode "abcdef"));
val it = SOME 2 : int option
- findPos #"z" (Array.fromList (explode "abcdef"));
val it = NONE : int option

Resources