State Monad - While-loops - f#

This question has been inspired by this question.
I understand the example (ListBuilder) but I have not been able to create a while loop for my state monad. What is not clear to me is how to bind the body of the whileloop as the iterations follow one an another.
Thank you.
/////////////////////////////////////////////////////////////////////////////////////
// Definition of the state
/////////////////////////////////////////////////////////////////////////////////////
type StateFunc<'State, 'T> = 'State -> 'T * 'State
/////////////////////////////////////////////////////////////////////////////////////
// Definition of the State monad
/////////////////////////////////////////////////////////////////////////////////////
type StateMonadBuilder<'State>() =
// M<'T> -> M<'T>
member b.ReturnFrom a : StateFunc<'State, 'T> = a
// 'T -> M<'T>
member b.Return a : StateFunc<'State, 'T> = ( fun s -> a, s)
// M<'T> * ('T -> M<'U>) -> M<'U>
member b.Bind(p : StateFunc<_, 'T>, rest : 'T -> StateFunc<_,_>) : StateFunc<'State, 'U> =
(fun s ->
let a, s' = p s
rest a s')
member b.Zero() = fun s -> (), s
member b.Delay f = f
member b.Run f = f ()
// Getter for the whole state, this type signature is because it passes along the state & returns the state
member b.getState : StateFunc<'State, _> = (fun s -> s, s)
// Setter for the state
member b.putState (s:'State) : StateFunc<'State, _> = (fun _ -> (), s)
// (unit -> bool) * M<'T> -> M<'T>
member b.While (cond, body: StateFunc<'State, _>): StateFunc<'State, _> =
(fun s ->
if cond () then
let bind =
let _, s' = body s
fun s' -> body s'
b.While (cond, bind) // This is wrong
else
body s)

If you look at the different computation builders in ExtCore, there is one interesting thing to note - for any monad, the implementation of While (and also For) member is usually the same.
This is because you can always express the operation in terms of Bind, Zero and recursive uses of While. So if you are working with monads, you will always define something like this (Just replace M<_> with your monad):
// (unit -> bool) * M<'T> -> M<'T>
member this.While (guard, body : M<_>) : M<_> =
if guard () then
this.Bind (body, (fun () -> this.While (guard, body)))
else
this.Zero ()
This is not true for all computations - if the computation is more interesting in some way, then it may need a different implementation of While, but the above is a reasonable default.
Aside - I think that the need to define custom computation expressions in F# should be quite rare - idiomatic F# code does not use monads nearly as often as e.g. Haskell and most of the time, you should be fine with what the standard library has (or what ExtCore defines, if you are doing something more advanced). Perhaps you need a custom computation, but keep in mind that this might be a distraction leading you in a wrong direction...

Related

F# Create Factorial function without recursion, library functions or loops

In this video about functional programming at 35:14 Jim Weirich writes a function to compute factorial without using recursion, library functions or loops:
see image of Ruby code here
The code in Ruby
fx = ->(improver) {
improver.(improver)
}.(
->(improver) {
->(n) { n.zero ? 1 : n * improver.(improver).(n-1) }
}
)
I'm trying to express this approach F#
let fx =
(fun improver -> improver(improver))(
fun improver ->
fun n ->
if n = 0 then 1
else n * improver(improver(n - 1)))
I'm currently stuck at
Type mismatch. Expecting a 'a but given a 'a -> 'b
The resulting type would be infinite when unifying ''a' and ''a -> 'b'
I can't seem find the right type annotation or other way of expressing the function
Edit:
*without the rec keyword
Languages with ML-style type inference won't be able to infer a type for the term fun improver -> improver improver; they start by assuming the type 'a -> 'b for a lambda-definition (for some undetermined types 'a and 'b), so as the argument improver has type 'a, but then it's applied to itself to give the result (of type 'b), so improver must simultaneously have type 'a -> 'b. But in the F# type system there's no way to unify these types (and in the simply-typed lambda calculus there's no way to give this term a type at all). My answer to the question that you linked to in your comment covers some workarounds. #desco has given one of those already. Another is:
let fx = (fun (improver:obj->_) -> improver improver)
(fun improver n ->
if n = 0 then 1
else n * (improver :?> _) improver (n-1))
This is cheating, but you can use types
type Self<'T> = delegate of Self<'T> -> 'T
let fx1 = (fun (x: Self<_>) -> x.Invoke(x))(Self(fun x -> fun n -> if n = 0 then 1 else x.Invoke(x)(n - 1) * n))
type Rec<'T> = Rec of (Rec<'T> -> 'T)
let fx2 = (fun (Rec(f ) as r) -> f r)(Rec(fun ((Rec f) as r) -> fun n -> if n = 0 then 1 else f(r)(n - 1) * n))

(How) can I make this monadic bind tail-recursive?

I have this monad called Desync -
[<AutoOpen>]
module DesyncModule =
/// The Desync monad. Allows the user to define in a sequential style an operation that spans
/// across a bounded number of events. Span is bounded because I've yet to figure out how to
/// make Desync implementation tail-recursive (see note about unbounded recursion in bind). And
/// frankly, I'm not sure if there is a tail-recursive implementation of it...
type [<NoComparison; NoEquality>] Desync<'e, 's, 'a> =
Desync of ('s -> 's * Either<'e -> Desync<'e, 's, 'a>, 'a>)
/// Monadic return for the Desync monad.
let internal returnM (a : 'a) : Desync<'e, 's, 'a> =
Desync (fun s -> (s, Right a))
/// Monadic bind for the Desync monad.
let rec internal bind (m : Desync<'e, 's, 'a>) (cont : 'a -> Desync<'e, 's, 'b>) : Desync<'e, 's, 'b> =
Desync (fun s ->
match (match m with Desync f -> f s) with
// ^--- NOTE: unbounded recursion here
| (s', Left m') -> (s', Left (fun e -> bind (m' e) cont))
| (s', Right v) -> match cont v with Desync f -> f s')
/// Builds the Desync monad.
type DesyncBuilder () =
member this.Return op = returnM op
member this.Bind (m, cont) = bind m cont
/// The Desync builder.
let desync = DesyncBuilder ()
It allows the implementation of game logic that executes across several game ticks to written in a seemingly sequential style using computation expressions.
Unfortunately, when used for tasks that last for an unbounded number of game ticks, it crashes with StackOverflowException. And even when it's not crashing, it's ending up with unwieldy stack traces like this -
InfinityRpg.exe!InfinityRpg.GameplayDispatcherModule.desync#525-20.Invoke(Nu.SimulationModule.Event<Prime.EitherModule.Either<Microsoft.FSharp.Core.Unit,Microsoft.FSharp.Core.Unit>,Nu.SimulationModule.Screen> _arg10) Line 530 F#
Prime.exe!Prime.DesyncModule.bind#20<Nu.SimulationModule.Event<Prime.EitherModule.Either<Microsoft.FSharp.Core.Unit,Microsoft.FSharp.Core.Unit>,Nu.SimulationModule.Screen>,Nu.SimulationModule.World,Microsoft.FSharp.Core.Unit,Nu.SimulationModule.Event<Prime.EitherModule.Either<Microsoft.FSharp.Core.Unit,Microsoft.FSharp.Core.Unit>,Nu.SimulationModule.Screen>>.Invoke(Nu.SimulationModule.World s) Line 24 F#
Prime.exe!Prime.DesyncModule.bind#20<Nu.SimulationModule.Event<Prime.EitherModule.Either<Microsoft.FSharp.Core.Unit,Microsoft.FSharp.Core.Unit>,Nu.SimulationModule.Screen>,Nu.SimulationModule.World,Microsoft.FSharp.Core.Unit,Microsoft.FSharp.Core.Unit>.Invoke(Nu.SimulationModule.World s) Line 21 F#
Prime.exe!Prime.DesyncModule.bind#20<Nu.SimulationModule.Event<Prime.EitherModule.Either<Microsoft.FSharp.Core.Unit,Microsoft.FSharp.Core.Unit>,Nu.SimulationModule.Screen>,Nu.SimulationModule.World,Microsoft.FSharp.Core.Unit,Microsoft.FSharp.Core.Unit>.Invoke(Nu.SimulationModule.World s) Line 21 F#
Prime.exe!Prime.DesyncModule.bind#20<Nu.SimulationModule.Event<Prime.EitherModule.Either<Microsoft.FSharp.Core.Unit,Microsoft.FSharp.Core.Unit>,Nu.SimulationModule.Screen>,Nu.SimulationModule.World,Microsoft.FSharp.Core.Unit,Microsoft.FSharp.Core.Unit>.Invoke(Nu.SimulationModule.World s) Line 21 F#
Prime.exe!Prime.DesyncModule.bind#20<Nu.SimulationModule.Event<Prime.EitherModule.Either<Microsoft.FSharp.Core.Unit,Microsoft.FSharp.Core.Unit>,Nu.SimulationModule.Screen>,Nu.SimulationModule.World,Microsoft.FSharp.Core.Unit,Microsoft.FSharp.Core.Unit>.Invoke(Nu.SimulationModule.World s) Line 21 F#
Prime.exe!Prime.DesyncModule.bind#20<Nu.SimulationModule.Event<Prime.EitherModule.Either<Microsoft.FSharp.Core.Unit,Microsoft.FSharp.Core.Unit>,Nu.SimulationModule.Screen>,Nu.SimulationModule.World,Microsoft.FSharp.Core.Unit,Microsoft.FSharp.Core.Unit>.Invoke(Nu.SimulationModule.World s) Line 21 F#
Prime.exe!Prime.DesyncModule.bind#20<Nu.SimulationModule.Event<Prime.EitherModule.Either<Microsoft.FSharp.Core.Unit,Microsoft.FSharp.Core.Unit>,Nu.SimulationModule.Screen>,Nu.SimulationModule.World,Microsoft.FSharp.Core.Unit,Microsoft.FSharp.Core.Unit>.Invoke(Nu.SimulationModule.World s) Line 21 F#
Prime.exe!Prime.DesyncModule.bind#20<Nu.SimulationModule.Event<Prime.EitherModule.Either<Microsoft.FSharp.Core.Unit,Microsoft.FSharp.Core.Unit>,Nu.SimulationModule.Screen>,Nu.SimulationModule.World,Microsoft.FSharp.Core.Unit,Microsoft.FSharp.Core.Unit>.Invoke(Nu.SimulationModule.World s) Line 21 F#
Prime.exe!Prime.Desync.step<Nu.SimulationModule.Event<Prime.EitherModule.Either<Microsoft.FSharp.Core.Unit,Microsoft.FSharp.Core.Unit>,Nu.SimulationModule.Screen>,Nu.SimulationModule.World,Microsoft.FSharp.Core.Unit>(Prime.DesyncModule.Desync<Nu.SimulationModule.Event<Prime.EitherModule.Either<Microsoft.FSharp.Core.Unit,Microsoft.FSharp.Core.Unit>,Nu.SimulationModule.Screen>,Nu.SimulationModule.World,Microsoft.FSharp.Core.Unit> m, Nu.SimulationModule.World s) Line 71 F#
Prime.exe!Prime.Desync.advanceDesync<Nu.SimulationModule.Event<Prime.EitherModule.Either<Microsoft.FSharp.Core.Unit,Microsoft.FSharp.Core.Unit>,Nu.SimulationModule.Screen>,Nu.SimulationModule.World,Microsoft.FSharp.Core.Unit>(Microsoft.FSharp.Core.FSharpFunc<Nu.SimulationModule.Event<Prime.EitherModule.Either<Microsoft.FSharp.Core.Unit,Microsoft.FSharp.Core.Unit>,Nu.SimulationModule.Screen>,Prime.DesyncModule.Desync<Nu.SimulationModule.Event<Prime.EitherModule.Either<Microsoft.FSharp.Core.Unit,Microsoft.FSharp.Core.Unit>,Nu.SimulationModule.Screen>,Nu.SimulationModule.World,Microsoft.FSharp.Core.Unit>> m, Nu.SimulationModule.Event<Prime.EitherModule.Either<Microsoft.FSharp.Core.Unit,Microsoft.FSharp.Core.Unit>,Nu.SimulationModule.Screen> e, Nu.SimulationModule.World s) Line 75 F#
Nu.exe!Nu.Desync.advance#98<Prime.EitherModule.Either<Microsoft.FSharp.Core.Unit,Microsoft.FSharp.Core.Unit>,Nu.SimulationModule.Screen>.Invoke(Nu.SimulationModule.Event<Prime.EitherModule.Either<Microsoft.FSharp.Core.Unit,Microsoft.FSharp.Core.Unit>,Nu.SimulationModule.Screen> event, Nu.SimulationModule.World world) Line 100 F#
Nu.exe!Nu.Desync.subscription#104-16<Prime.EitherModule.Either<Microsoft.FSharp.Core.Unit,Microsoft.FSharp.Core.Unit>,Nu.SimulationModule.Screen>.Invoke(Nu.SimulationModule.Event<Prime.EitherModule.Either<Microsoft.FSharp.Core.Unit,Microsoft.FSharp.Core.Unit>,Nu.SimulationModule.Screen> event, Nu.SimulationModule.World world) Line 105 F#
Nu.exe!Nu.World.boxableSubscription#165<Prime.EitherModule.Either<Microsoft.FSharp.Core.Unit,Microsoft.FSharp.Core.Unit>,Nu.SimulationModule.Screen>.Invoke(object event, Nu.SimulationModule.World world) Line 166 F#
I am hoping to solve the problem by making the Left case of the bind function tail-recursive. However, I'm not sure of two things -
1) if it can be done at all, and
2) how it would actually be done.
If it's impossible to make bind tail-recursive here, is there some way to restructure my monad to allow it to become tail-recursive?
EDIT 3 (subsumes previous edits): Here is additional code that implements the desync combinators I will use to demonstrate the stack overflow -
module Desync =
/// Get the state.
let get : Desync<'e, 's, 's> =
Desync (fun s -> (s, Right s))
/// Set the state.
let set s : Desync<'e, 's, unit> =
Desync (fun _ -> (s, Right ()))
/// Loop in a desynchronous context while 'pred' evaluate to true.
let rec loop (i : 'i) (next : 'i -> 'i) (pred : 'i -> 's -> bool) (m : 'i -> Desync<'e, 's, unit>) =
desync {
let! s = get
do! if pred i s then
desync {
do! m i
let i = next i
do! loop i next pred m }
else returnM () }
/// Loop in a desynchronous context while 'pred' evaluates to true.
let during (pred : 's -> bool) (m : Desync<'e, 's, unit>) =
loop () id (fun _ -> pred) (fun _ -> m)
/// Step once into a desync.
let step (m : Desync<'e, 's, 'a>) (s : 's) : 's * Either<'e -> Desync<'e, 's, 'a>, 'a> =
match m with Desync f -> f s
/// Run a desync to its end, providing e for all its steps.
let rec runDesync (m : Desync<'e, 's, 'a>) (e : 'e) (s : 's) : ('s * 'a) =
match step m s with
| (s', Left m') -> runDesync (m' e) e s'
| (s', Right v) -> (s', v)
Here is the Either implementation -
[<AutoOpen>]
module EitherModule =
/// Haskell-style Either type.
type Either<'l, 'r> =
| Right of 'r
| Left of 'l
And finally, here's simple a line of code that will yield a stack overflow -
open Desync
ignore <| runDesync (desync { do! during (fun _ -> true) (returnM ()) }) () ()
It seems to me your monad is a State with error handling.
It's basically ErrorT< State<'s,Either<'e,'a>>> but the error branch binds again which is not very clear to me why.
Anyway I was able to reproduce your Stack Overflow with a basic State monad:
type State<'S,'A> = State of ('S->('A * 'S))
module State =
let run (State x) = x :'s->_
let get() = State (fun s -> (s , s)) :State<'s,_>
let put x = State (fun _ -> ((), x)) :State<'s,_>
let result a = State(fun s -> (a, s))
let bind (State m) k = State(fun s ->
let (a, s') = m s
let (State u) = (k a)
u s') :State<'s,'b>
type StateBuilder() =
member this.Return op = result op
member this.Bind (m, cont) = bind m cont
let state = StateBuilder()
let rec loop (i: 'i) (next: 'i -> 'i) (pred: 'i -> 's -> bool) (m: 'i -> State<'s, unit>) =
state {
let! s = get()
do! if pred i s then
state {
do! m i
let i = next i
do! loop i next pred m }
else result () }
let during (pred : 's -> bool) (m : State<'s, unit>) =
loop () id (fun _ -> pred) (fun _ -> m)
// test
open State
ignore <| run (state { do! during (fun c -> true) (result ()) }) () // boom
As stated in the comments one way to solve this is to use a StateT<'s,Cont<'r,'a>>.
Here's an example of the solution. At the end there is a test with the zipIndex function which blows the stack as well when defined with a normal State monad.
Note you don't need to use the Monad Transformers from FsControl (now FSharpPlus), I use them because it's easier for me since I write less code but you can always create your transformed monad by hand.

type inference of (>>)(>>) (function composition)

I have seen somewhere (sorry, I can't find the a reference) this operator composition:
(>>)(>>)
where (>>): (('a -> 'b) -> ('b -> 'c) -> 'a -> 'c) - (>>) is the function composition operator.
I find simpler examples are easy to understand. For example (>>)f, where f: i -> i.
(>>)(i -> i) becomes (i -> 't) -> i -> 't. This is because ('a -> 'b) is curried away, 'b is inferred to be i and 't remains a generic type.
I do not fully understand (>>)(>>):
The use
What would (>>)(>>) and (<<)(<<) used for?
Why it is necessary to make the argument explicit?
> (>>)(>>);;
(>>)(>>);;
-^^^^^^
C:\Users\...\Temp\stdin(3,2): error FS0030: Value restriction. The value 'it' has been inferred to have generic type
val it : (((('_a -> '_b) -> '_c -> '_b) -> '_d) -> ('_c -> '_a) -> '_d)
Either make the arguments to 'it' explicit or, if you do not intend for it to be generic, add a type annotation.
As suggested by the error message:
> let strangeFun arg = (>>)(>>) arg;;
val strangeFun : arg:((('a -> 'b) -> 'c -> 'b) -> 'd) -> (('c -> 'a) -> 'd)
There have been several explanations of value restriction around here in the past; here is one I wrote that explains why it is necessary. For completeness I'll copy here the example code that would be incorrect if the value restriction was removed:
let f : 'a -> 'a option =
let r = ref None
fun x ->
let old = !r
r := Some x
old
f 3 // r := Some 3; returns None : int option
f "t" // r := Some "t"; returns Some 3 : string option!!!
As far as what (>>)(>>) would be used for, I admit I don't know. There is however a similar-looking but useful function, which is (<<) << (<<) (better known in Haskell as (.).(.)), which returns a similar composition operator whose second and returned functions can take two arguments instead of one.
let (<<<<) f = ((<<) << (<<)) f;;
// val ( <<<< ) : f:('a -> 'b) -> (('c -> 'd -> 'a) -> 'c -> 'd -> 'b)

Recursively update a State Monad

this question is related to this question
I have a state monad. An object provides an update function as in the OOD strategy pattern.
The choice of having a object is that in real, production code, the
class provides an array of operations, all sharing state through the
monad. Inheritance helped me extend the basic functionality and
further customizing the class providing the operations.
The choice of having a monad instead of a mutable property within the class is that the monad, through proper use of generics, is helping me abstracting and being more flexible on what variables/information must be carried along the computation as "state".
I have a simple toy example:
/////////////////////////////////////////////////////////////////////////////////////
// Definition of the state
/////////////////////////////////////////////////////////////////////////////////////
type StateFunc<'State, 'T> = 'State -> 'T * 'State
/////////////////////////////////////////////////////////////////////////////////////
// Definition of the State monad type
/////////////////////////////////////////////////////////////////////////////////////
type StateMonadBuilder<'State>() =
// M<'T> -> M<'T>
member b.ReturnFrom a : StateFunc<'State, 'T> = a
// 'T -> M<'T>
member b.Return a : StateFunc<'State, 'T> = ( fun s -> a, s)
// M<'T> * ('T -> M<'U>) -> M<'U>
member b.Bind(p : StateFunc<_, 'T>, rest : 'T -> StateFunc<_,_>) : StateFunc<'State, 'U> =
(fun s ->
let a, s' = p s
rest a s')
// Getter for the whole state, this type signature is because it passes along the state & returns the state
member b.getState : StateFunc<'State, _> = (fun s -> s, s)
// Setter for the state
member b.putState (s:'State) : StateFunc<'State, _> = (fun _ -> (), s)
let runState f init = f init
/////////////////////////////////////////////////////////////////////////////////////
// STRATEGY PATTERN
/////////////////////////////////////////////////////////////////////////////////////
let state = StateMonadBuilder<int> ()
// DoubleFunctOne defines standard operations that remain always the same
type Strategy (aFunction) =
member this.Update (x: int) = state {
let! currState = state.getState
let processedx = aFunction x
do! state.putState (currState + x) }
// Create a function that customizes the strategy
let myFunction x =
2 * x
// Customize the strategy with the desired function:
let strategy = Strategy (myFunction)
/////////////////////////////////////////////////////////////////////////////////////////////////////////
// Update recursively
/////////////////////////////////////////////////////////////////////////////////////////////////////////
// ?? How to run update recursively ??
let result initialCondition =
initialCondition
|> (for i = 10 to 100 do
yield state { do! strategy.Update i } )
My goal is to apply the initial conditions, fetch data and launch recursively (within a for or a while loop or even some functional operation) the functions provided by strategy. Working with the monad, I am not sure how to do this.
Thank you.
Computational Expression For
Inspired by #kvb answer, I have added a for method to the computational expression.
// Loops through seqnc of numbers that constitute an input to func
member b.For (seqnc:_ List, func) =
seqnc
|> List.map (fun item -> func item)
|> List.reduce (fun acc item ->
(fun s ->
let _, s' = acc s
item s' ) )
I run a few tests and I have the impression that this one works.
Thanks.
Something like this?
let result initialCondition =
let rec loop = function
| 101 -> state { return () }
| i ->
state {
do! strategy.Update i
do! loop (i+1)
}
initialCondition
|> runState (loop 10)
Alternatively, define a For member on your builder and write it the more imperative way:
let result initialCondition =
let f = state {
for i in 10 to 100 do
do! strategy.Update i
}
initialCondition
|> runState f
Also, note that there is likely a bug in your definition of Strategy.Update: processedx is bound but unused.

Built in f# operator to compose functions with the same input but different outputs?

I understand the << compose operator takes two functions that both take in and return the same type. e.g. (lhs:'a -> 'a) -> (rhs:'a -> 'a) -> 'a
I often find myself wanting something like (lhs:'a -> 'b) -> (rhs:'c -> 'b) -> 'b in cases where I'm interested in side affects and not the return value 'b is probably the unit type. This is only when I have two lines in succession where I'm persisting something to a database.
Is there a built in function or idiomatic F# way of doing this without writing something like
let myCompose lhs rhs arg =
lhs arg
rhs arg
Backward composition operator (<<) is defined as:
( << ) : ('b -> 'c) -> ('a -> 'b) -> 'a -> 'c`
With two predicates applied, it is actually a function that takes initial value of 'a returning 'c, while the value of 'b is processed inside.
From the code sample you provided, let me assume that you need applying an argument to both predicates. There are several ways to do this:
Discarding the value returned by the (first) predicate, returning the original argument instead. Such operator exists in WebSharper:
let ( |>! ) x f = f x; x
// Usage:
let ret =
x
|>! f1
|>! f2
|> f3
I like this approach because:
it does not complicate things; each function application is atomic, and the code appears more readable;
it allows chaining throughout three or more predicates, like in the example above;
In this case, f must return unit, but you can easily work this around:
let ( |>!! ) x f = ignore(f x); x
Applying the argument to both predicates, returning a tuple of results, exactly as in your own example. There's such operator OCaml, easy to adapt to F#:
val (&&&) : ('a -> 'b) -> ('a -> 'c) -> 'a -> 'b * 'c
As #JackP noticed, &&& is already defined in F# for another purpose, so let's use another name:
/// Applying two functions to the same argument.
let (.&.) f g x = (f x, g x)
// Usage
let ret1, ret2 =
x
|> (f .&. g)
Note The samples above are for straight order of function application. If you need them applied in a reverse order, you need to modify the code accordingly.
The backward or reverse composition operator (<<) does not take two functions that both take in and return the same type; the only constraint is that the output type of the first function to be applied must be the same as the input type of the function it's being composed into. According to MSDN, the function signature is:
// Signature:
( << ) : ('T2 -> 'T3) -> ('T1 -> 'T2) -> 'T1 -> 'T3
// Usage:
func2 << func1
I don't know of a built-in composition operator that works like you want, but if this pattern is something you use frequently in your code and having such an operator would simplify your code, I think it's reasonable to define your own. For example:
> let (<<!) func2 func1 arg = func1 arg; func2 arg;;
val ( <<! ) : func2:('a -> 'b) -> func1:('a -> unit) -> arg:'a -> 'b
Or, if you know both functions are going to return unit, you can write it like this to constrain the output type to be unit:
> let (<<!) func2 func1 arg = func1 arg; func2 arg; ();;
val ( <<! ) : func2:('a -> unit) -> func1:('a -> unit) -> arg:'a -> unit
For composing of any number of functions of type f:'a->unit in any desired order you may simply fold their list:
("whatever",[ printfn "funX: %A"; printfn "funY: %A"; printfn "funZ: %A" ])
||> List.fold (fun arg f -> f arg; arg )
|> ignore
getting in FSI
funX: "whatever"
funY: "whatever"
funZ: "whatever"
val it : unit = ()

Resources