I have a pure function that takes 18 arguments process them and returns an answer.
Inside this function I call many other pure functions and those functions call other pure functions within them as deep as 6 levels.
This way of composition is cumbersome to test as the top level functions,in addition to their logic,have to gather parameters for inner functions.
# Minimal conceptual example
main_function(a, b, c, d, e) = begin
x = pure_function_1(a, b, d)
y = pure_function_2(a, c, e, x)
z = pure_function_3(b, c, y, x)
answer = pure_function_4(x,y,z)
return answer
end
# real example
calculate_time_dependant_losses(
Ap,
u,
Ac,
e,
Ic,
Ep,
Ecm_t,
fck,
RH,
T,
cementClass::Char,
ρ_1000,
σ_p_start,
f_pk,
t0,
ts,
t_start,
t_end,
) = begin
μ = σ_p_start / f_pk
fcm = fck + 8
Fr = σ_p_start * Ap
_σ_pb = σ_pb(Fr, Ac, e, Ic)
_ϵ_cs_t_start_t_end = ϵ_cs_ti_tj(ts, t_start, t_end, Ac, u, fck, RH, cementClass)
_ϕ_t0_t_start_t_end = ϕ_t0_ti_tj(RH, fcm, Ac, u, T, cementClass, t0, t_start, t_end)
_Δσ_pr_t_start_t_end =
Δσ_pr(σ_p_start, ρ_1000, t_end, μ) - Δσ_pr(σ_p_start, ρ_1000, t_start, μ)
denominator =
1 +
(1 + 0.8 * _ϕ_t0_t_start_t_end) * (1 + (Ac * e^2) / Ic) * ((Ep * Ap) / (Ecm_t * Ac))
shrinkageLoss = (_ϵ_cs_t_start_t_end * Ep) / denominator
relaxationLoss = (0.8 * _Δσ_pr_t_start_t_end) / denominator
creepLoss = (Ep * _ϕ_t0_t_start_t_end * _σ_pb) / Ecm_t / denominator
return shrinkageLoss + relaxationLoss + creepLoss
end
I see examples of functional composition (dot chaining,pipe operator etc) with single argument functions.
Is it practical to compose the above function using functional programming?If yes, how?
The standard and simple way is to recast your example so that it can be written as
# Minimal conceptual example, re-cast
main_function(a, b, c, d, e) = begin
x = pure_function_1'(a, b, d)()
y = pure_function_2'(a, c, e)(x)
z = pure_function_3'(b, c)(y) // I presume you meant `y` here
answer = pure_function_4(z) // and here, z
return answer
end
Meaning, we use functions that return functions of one argument. Now these functions can be easily composed, using e.g. a forward-composition operator (f >>> g)(x) = g(f(x)) :
# Minimal conceptual example, re-cast, composed
main_function(a, b, c, d, e) = begin
composed_calculation =
pure_function_1'(a, b, d) >>>
pure_function_2'(a, c, e) >>>
pure_function_3'(b, c, y) >>>
pure_function_4
answer = composed_calculation()
return answer
end
If you really need the various x y and z at differing points in time during the composed computation, you can pass them around in a compound, record-like data structure. We can avoid the coupling of this argument handling if we have extensible records:
# Minimal conceptual example, re-cast, composed, args packaged
main_function(a, b, c, d, e) = begin
composed_calculation =
pure_function_1'(a, b, d) >>> put('x') >>>
get('x') >>> pure_function_2'(a, c, e) >>> put('y') >>>
get('x') >>> pure_function_3'(b, c, y) >>> put('z') >>>
get({'x';'y';'z'}) >>> pure_function_4
answer = composed_calculation(empty_initial_state)
return value(answer)
end
The passed around "state" would be comprised of two fields: a value and an extensible record. The functions would accept this state, use the value as their additional input, and leave the record unchanged. get would take the specified field out of the record and put it in the "value" field in the state. put would mutate the extensible record in the state:
put(field_name) = ( {value:v ; record:r} =>
{v ; put_record_field( r, field_name, v)} )
get(field_name) = ( {value:v ; record:r} =>
{get_record_field( r, field_name) ; r} )
pure_function_2'(a, c, e) = ( {value:v ; record:r} =>
{pure_function_2(a, c, e, v); r} )
value(r) = get_record_field( r, value)
empty_initial_state = { novalue ; empty_record }
All in pseudocode.
Augmented function application, and hence composition, is one way of thinking about "what monads are". Passing around the pairing of a produced/expected argument and a state is known as State Monad. The coder focuses on dealing with the values while treating the state as if "hidden" "under wraps", as we do here through the get/put etc. facilities. Under this illusion/abstraction, we do get to "simply" compose our functions.
I can make a small start at the end:
sum $ map (/ denominator)
[ _ϵ_cs_t_start_t_end * Ep
, 0.8 * _Δσ_pr_t_start_t_end
, (Ep * _ϕ_t0_t_start_t_end * _σ_pb) / Ecm_t
]
As mentioned in the comments (repeatedly), the function composition operator does indeed accept multiple argument functions. Cite: https://docs.julialang.org/en/v1/base/base/#Base.:%E2%88%98
help?> ∘
"∘" can be typed by \circ<tab>
search: ∘
f ∘ g
Compose functions: i.e. (f ∘ g)(args...; kwargs...) means f(g(args...; kwargs...)). The ∘ symbol
can be entered in the Julia REPL (and most editors, appropriately configured) by typing
\circ<tab>.
Function composition also works in prefix form: ∘(f, g) is the same as f ∘ g. The prefix form
supports composition of multiple functions: ∘(f, g, h) = f ∘ g ∘ h and splatting ∘(fs...) for
composing an iterable collection of functions.
The challenge is chaining the operations together, because any function can only pass on a tuple to the next function in the composed chain. The solution could be making sure your chained functions 'splat' the input tuples into the next function.
Example:
# splat to turn max into a tuple-accepting function
julia> f = (x->max(x...)) ∘ minmax;
julia> f(3,5)
5
Using this will in no way help make your function cleaner, though, in fact it will probably make a horrible mess.
Your problems do not at all seem to me to be related to how you call, chain or compose your functions, but are entirely due to not organizing the inputs in reasonable types with clean interfaces.
Edit: Here's a custom composition operator that splats arguments, to avoid the tuple output issue, though I don't see how it can help picking the right arguments, it just passes everything on:
⊕(f, g) = (args...) -> f(g(args...)...)
⊕(f, g, h...) = ⊕(f, ⊕(g, h...))
Example:
julia> myrev(x...) = reverse(x);
julia> (myrev ⊕ minmax)(5,7)
(7, 5)
julia> (minmax ⊕ myrev ⊕ minmax)(5,7)
(5, 7)
Idris language tutorial has simple and understandable example of the idea of Dependent Types:
http://docs.idris-lang.org/en/latest/tutorial/typesfuns.html#first-class-types
Here is the code:
isSingleton : Bool -> Type
isSingleton True = Int
isSingleton False = List Int
mkSingle : (x : Bool) -> isSingleton x
mkSingle True = 0
mkSingle False = []
sum : (single : Bool) -> isSingleton single -> Int
sum True x = x
sum False [] = 0
sum False (x :: xs) = x + sum False xs
I decided to spend more time on this example. What bothers me in sum function is that I need to explicitly pass single : Bool value to function. I don't want to do this and I want compiler to guess what this boolean value should be. Hence I pass only Int or List Int to sum function there should be 1-to-1 correspondence between boolean value and type of argument (if I pass some other type this just mustn't type check).
Of course, I understand, this is not possible in general case. Such compiler tricks require my function isSingleton (or any other similar function) be injective. But for this case it should be possible as it seems to me...
So I started with next implementation: I just made single argument implicit.
sum : {single : Bool} -> isSingleton single -> Int
sum {single = True} x = x
sum {single = False} [] = 0
sum {single = False} (x :: xs) = x + sum' {single = False} xs
Well, it doesn't really solve my problem because I still need to call this function in the next way:
sum {single=True} 1
But I read in tutorial about auto keyword. Though I don't quite understand what auto does (because I didn't find description of it) I decided to patch my function just a little bit more:
sum' : {auto single : Bool} -> isSingleton single -> Int
sum' {single = True} x = x
sum' {single = False} [] = 0
sum' {single = False} (x :: xs) = x + sum' {single = False} xs
And it works for lists!
*DepFun> :t sum'
sum' : {auto single : Bool} -> isSingleton single -> Int
*DepFun> sum' [1,2,3]
6 : Int
But doesn't work for single value :(
*DepFun> sum' 3
When checking an application of function Main.sum':
List Int is not a numeric type
Can someone explain is it actually possible to achieve my goal in such injective function usages currently? I watched this short video about proving something is injective:
https://www.youtube.com/watch?v=7Ml8u7DFgAk
But I don't understand how I can use such proofs in my example.
If this is not possible what is the best way to write such functions?
The auto keyword basically tells Idris, "Find me any value of this type". So you're liable to get the wrong answer unless that type only contains one value. Idris sees {auto x : Bool} and fills it in with any old Bool, namely False. It doesn't use its knowledge of later arguments to help it choose - information doesn't flow from right to left.
One fix would be to make the information flow in the other direction. Rather using a universe-style construction as you have above, write a function accepting an arbitrary type and use a predicate to refine it to the two options you want. This way Idris can look at the type of the preceding argument and pick the only value of IsListOrInt whose type matches.
data IsListOrInt a where
IsInt : IsListOrInt Int
IsList : IsListOrInt (List Int)
sum : a -> {auto isListOrInt : IsListOrInt a} -> Int
sum x {IsInt} = x
sum [] {IsList} = 0
sum (x :: xs) {IsList} = x + sum xs
Now, in this case the search space is small enough (two values - True and False) that Idris could feasibly explore every option in a brute-force fashion and pick the first one that results in a program which passes the type checker, but that algorithm doesn't scale well when the types are much bigger than two, or when trying to infer multiple values.
Compare the left-to-right nature of the information flow in the above example with the behaviour of regular non-auto braces, which instruct Idris to find the result in a bidirectional fashion using unification. As you note, this could only succeed when the type functions in question are injective. You could structure your input as a separate, indexed datatype, and allow Idris to look at the constructor to find b using unification.
data OneOrMany isOne where
One : Int -> OneOrMany True
Many : List Int -> OneOrMany False
sum : {b : Bool} -> OneOrMany b -> Int
sum (One x) = x
sum (Many []) = 0
sum (Many (x :: xs)) = x + sum (Many xs)
test = sum (One 3) + sum (Many [29, 43])
Predicting when the machine will or won't be able to guess what you mean is an important skill in dependently-typed programming; you'll find yourself getting better at it with more experience.
Of course, in this case it's all moot because lists already have one-or-many semantics. Write your function over plain old lists; then if you need to apply it to a single value you can just wrap it in a singleton list.
I have noticed that there are 2 ways of defining functions in SML. For example if you take the add function, these are the two ways:
fun add x y = x+y;
fun add(x,y) = x+y;
The first method creates the function type as:
val add = fn : int -> int -> int
The second one creates the function type as:
val add = fn : int * int -> int
What is the difference between these two types for the same function? And also why are there two types for the same function?
If we remove the syntactic sugar from your two definitions they become:
val add = fn x => fn y => x+y
and
val add = fn xy =>
case xy of
(x,y) => x+y
So in the first case add is a function that takes an argument x and returns another function, which takes an argument y and then returns x+y. This technique of simulating multiple arguments by returning another function is known as currying.
In the second case add is a function that takes a tuple as an argument and then adds the two elements of the tuple.
This also explains the two different types. -> is the function arrow, which associates to the right, meaning int -> int -> int is the same as int -> (int -> int) describing a function that takes an int and returns an int -> int function.
* on the other hand is the syntax used for tuple types, that is int * int is the type of tuples containing two ints, so int * int -> int (which is parenthesized as (int * int) -> int because * has higher precedence than ->) describes a function that takes a tuple of two ints and returns an int.
The reason those 2 functions are different is because of the phenomenon of Currying. Specifically, Currying is the ability to write any function with dom(f) = R^{n} as a function that takes inputs from R n-times. This basically is accomplished by ensuring that each input returns a function for the next variable to take in. This is what the -> sign represents - It's a fundamental result from the Curry-Howard Isomorphism. So :
fun addCurry x y = x + y (* int -> int -> int *)
fun addProd (x,y) = x + y (* (int*int) -> int *)
tells us that addCurry is the reduction of addProd into a form that can be used to "substitute" and return variables. So, addProd and addCurry are Contextually-Equivalent. However, they are not Semantically-Equivalent.
(int*int) is a product-type. It says that it expects input1=int and input2=int. int -> int says that it takes an int and returns an int. It's an arrow-type.
If you're interested, you may also want to know that there are only 2 kinds of arguments to SML functions :
1) Curried
2) Tuples - So, fun addProd (x,y) represents (x,y) as a tuple to the function argument.
I'm learning functional programming and am using Ocaml, but I'm having a bit of a problem with functions.
Anyway, I have a tuple and I want to return its first value. (Very simple I know, sorry)
let bach (x,y):(float*float) = (x,y);;
val bach : float * float -> float * float = <fun>
All well and good up here.
let john (x,y):(float*float) = y;;
val john : 'a * (float * float) -> float * float = <fun>
Now this is what confuses me. Why is there a 'a there? I know that it stands for a variable with an unknown type, but I'm confused as to how changing the return value adds that there.
I am a self professed n00b in functional programming, please don't eat me :)
You were bitten by a subtle syntax mistake that is really non-obvious for beginners:
let foo x : t = bar
is not the same as
let foo (x : t) = bar
it is on the contrary equivalent to
let foo x = (bar : t)
constraining the return type of the function.
.
So you have written
let john (x, y) = (y : float * float)
The input type is a pair whose second element, y, has type float * float. But x can be of any type, so the function is polymorphic in its type, which it represents as a type variable 'a. The type of the whole function, 'a * (float * float) -> float * float, indicates that for any type 'a, you may pass a tuple of an 'a and a (float * float), and it will return a (float * float).
This is a particular case of the snd function:
let snd (x, y) = y
which has type 'a * 'b -> 'b: for any 'a and 'b, you take a pair ('a * 'b) and return a value of type 'b.
In both of your examples you are giving type-constraints for the result of the defined function, instead of its argument (as was probably intended).
Thus
let john (x, y) : (float * float) = y;;
means that the result of john (i.e., y) should be of type (float * float). Now, since in the input we have a pair consisting of x (of which nothing is known) and y (of type float * float), the final type for the input is 'a * (float * flat).
To get what you want, you could use:
let john ((x:float), (y:float)) = y;;
If you want to learn Ocaml and functional programming in general, Programming Languages course is going to be offered at Coursera again. You will learn programming language concepts by SML, Racket and Ruby and have fun assignments to apply what you learn. Highly recommended.
All,
Here is the type expression which I need to convert to a ML expression:
int -> (int*int -> 'a list) -> 'a list
Now I know this is a currying style expression which takes 2 arguments:
1st argument = Type int
and 2nd argument = Function which takes the previous int value twice and return a list of any type
I am having a hard time figuring such a function that would take an int and return 'a list.
I am new to ML and hence this might be trivial to others, but obviously not me.
Any help is greatly appreciated.
You get an int and a function int*int -> 'a list. You're supposed to return an 'a list. So all you need to do is call the function you get with (x,x) (where x is the int you get) and return the result of that. So
fun foo x f = f (x,x)
Note that this is not the only possible function with type int -> (int*int -> 'a list) -> 'a list. For example the functions fun foo x f = f (x, 42) and fun foo x f = f (23, x) would also have that type.
Edit:
To make the type match exactly add a type annotation to restrict the return type of f:
fun foo x (f : int*int -> 'a list) = f (x,x)
Note however that there is no real reason to do that. This version behaves exactly as the one before, except that it only accepts functions that return a list.