The API design philosophy in OCaml - functional-programming

After learning OCaml for like half year, I am still struggling at the functional programming and imperative programming bits.
It is not about using list or array, but about API design.
For example, if I am about to write stack for a user, should I present it in functional or imperative way?
stack should have a function called pop, which means return the last element to user and remove it from the stack. So if I design my stack in functional way, then for pop, I should return a tuple (last_element, new_stack), right? But I think it is ugly.
At the same time, I feel functional way is more natural in Functional Programming.
So, how should I handle this kind of design problem?
Edit
I saw stack's source code and they define the type like this:
type 'a t = { mutable c : 'a list }
Ok, internally the standard lib uses list which is immutable, but the encapsulate it in a mutable record.
I understand this as in this way, for the user, it is always one stack and so no need for a tuple to return to the client.
But still, it is not a functional way, right?

Mutable structures are sometimes more efficient, but they're not persistent, which is useful in various situations (mostly for backtracking a failed computation). If the immutable interface has no or little performance overhead over the mutable interface, you should absolutely prefer the immutable one.

Functionally (i.e. without mutability), you can either define it exactly like List by using head/tail rather than pop, or you can, as you suggest, let the API handle state change by returning a tuple. This is comparable to how state monads are built.
So either it is the responsibility of the parent scope to handle the stack's state (e.g. through recursion), in which case stacks are exactly like lists, or some of this responsibility is loaded to the API through tuples.
Here is a quick attempt (pretending to know O'Caml syntax):
module Stack =
struct
type 'a stack = 'a list
let empty _ = ((), [])
let push x stack = ((), x::stack)
let pop (x::stack) = (x, stack)
| pop _ = raise EmptyStack
end
One use case would then be:
let (_, st) = Stack.empty ()
let (_, st) = Stack.push 1 Stack.empty
let (_, st) = Stack.push 2 st
let (_, st) = Stack.push 3 st
let (x, st) = Stack.pop st
Instead of handling the tuples explicitly, you may want to hide passing on st all the time and invent an operator that makes the following syntax possible:
let (x, st) = (Stack.empty >>= Stack.push 1 >>=
Stack.push 2 >>= Stack.push 3 >>= Stack.pop) []
If you can make this operator, you have re-invented the state monad. :)
(Because all of the functions above take a state as its curried last argument, they can be partially applied. To expand on this, so it is more apparent what is going on, but less readable, see the rewrite below.)
let (x, st) = (fun st -> Stack.empty st >>= fun st -> Stack.push 1 st
>>= fun st -> Stack.push 2 st
>>= fun st -> Stack.push 3 st
>>= fun st -> Stack.pop) []
This is one idiomatic way to deal with state and immutable data structures, at least.

Related

What is the difference between a writer monad and a list writer monad

I was looking at the examples of writer monad to understand how it works and almost all of those looks like a list writer monad. I know a list writer monad is a type of writer monad. But what really is a writer monad in lay-mans terms.
In lay terms, the writer monad is the monad that lets you "write" items to a "log" while you produce a value. When you're done, you end up with the value you produced and the log that contains all the stuff you wrote. To put it another way, it is the monad whose side effects are "writing things to a log".
Let's make this more concrete with examples of both the list writer and the (generic) writer monads. I'll use Haskell here, since it is the original context in which Monads for Functional Programming were described.
The List Writer Monad
I assume that the "list writer" monad is one that logs an item (of some type we'll call w) into a list of items (of type [w], of course). It also produces a value of type a. (See the note at the bottom if you get errors using this code yourself.)
newtype ListWriter w a = ListWriter { runListWriter :: ([w], a) }
instance Monad (ListWriter w) where
return a = ListWriter ([], a) -- produce an a, don't log anything
ListWriter (ws, a) >>= k =
let ListWriter (xs, a') = k a -- run the action 'k' on the existing value,
in ListWriter (ws ++ xs, a') -- add anything it logs to the existing log,
-- and produce a new result value
-- Add an item to the log and produce a boring value.
-- When sequenced with >>, this will add the item to existing log.
tell :: w -> ListWriter w ()
tell w = ListWriter ([w], ())
ex1 :: ListWriter String Int
ex1 = do
tell "foo"
tell "bar"
return 0
(NB: This is equivalent to ex1 = tell "foo" >> tell "bar" >> return 0, demonstrating the use of tell with >> to add an item to the log.)
If we evaluate runListWriter ex1 in GHCi, we see that it wrote "foo" and "bar" to the log and produced the result value 0.
λ> runListWriter ex1
(["foo","bar"],0)
The (Generic) Writer Monad
Now, let's see how we turn this into the generic writer monad. The writer monad works with any sort of thing that can be combined together, not just a list. Specifically, it works with any Monoid:
class Monoid m where
mempty :: m -- an empty m
mappend :: m -> m -> m -- combine two m's into a single m
Lists are a Monoid with [] and (++) as mempty and mappend respectively. A non-list example of a Monoid is sums of integers:
λ> Sum 1 <> Sum 2 -- (<>) = mappend
Sum {getSum = 3}
The writer monad is then
newtype Writer w m = Writer { runWriter :: (w, m) }
Instead of a list of w's, we just have a single w. But when we define the Monad, we ensure that w is a Monoid so we can start with an empty log and append a new entry to the log:
instance Monoid w => Monad (Writer w) where
return a = Writer (mempty, a) -- produce an a, don't log anything
Writer (w, a) >>= k =
let Writer (x, a') = k a -- we combine the two w's rather than
in Writer (w <> x, a') -- (++)-ing two lists
Note the differences here: we use mempty instead of [] and (<>) instead of (++). This is how we generalize from lists to any Monoid.
So the writer monad is really a generalization of the list monad to arbitrary things that can be combined rather than just lists. You can use lists with the Writer to get something (almost) equivalent to ListWriter. The only difference is that you have to wrap your logged item in a list when you append it to the log:
ex2 :: Writer [String] Int
ex2 = do
tell ["foo"]
tell ["bar"]
return 0
but you get the same result:
λ> runWriter ex2
(["foo","bar"],0)
This is because instead of logging "an item that will be put in a list", you are logging "a list". (This does mean that you can log multiple items at the same time by passing a list of more than one element.)
For an example of a non-list use of Writer, consider counting the comparisons a sort function makes. Each time your function make a comparison, you can tell (Sum 1). (You can tell someone. Get it? Is this thing on?) Then, at the end, you'll get back the total count (i.e., the sum) of all of the comparisons along with the sorted list.
NOTE: If you try to use these ListWriter and Writer definitions yourself, GHC will tell you that you are missing Functor and Applicative instances. Once you have the Monad instance, you can write the others in its terms:
import Control.Monad (ap, liftM)
instance Functor (ListWriter w) where
fmap = liftM
instance Applicative (ListWriter w) where
pure = return
(<*>) = ap
And likewise for Writer. I elided them above for clarity.

isolate in SMLofNJ.Cont

I was reading about continuations in Standard ML (SMLofNJ.Cont). I understood what callcc and throw does, but could not understand isolate. The documentation says
Discard all live data from the calling context (except what is reachable from f or x), then call f(x), then exit. This may use much less memory then something like f(x) before exit().
However this does not make any sense to me. I just wanted to know what this function does, with some examples.
MLton does a better job of explaining an implementation of isolate using callcc and throw:
val isolate: ('a -> unit) -> 'a t =
fn (f: 'a -> unit) =>
callcc
(fn k1 =>
let
val x = callcc (fn k2 => throw (k1, k2))
val _ = (f x ; Exit.topLevelSuffix ())
handle exn => MLtonExn.topLevelHandler exn
in
raise Fail "MLton.Cont.isolate: return from (wrapped) func"
end)
We use the standard nested callcc trick to return a continuation that is ready to receive an argument, execute the isolated function, and exit the program. [...]
The page continues to explain how to achieve the same effect with less space leaking.
MLton's CONT signature has a different documentation line than SML/NJ's CONT signature:
isolate f creates a continuation that evaluates f in an empty context.
This is a constant time operation, and yields a constant size stack.

"Subsetting" a dictionary in F#

I'm a beginner in F# and I'm trying to write a function to subset a dictionary given list, and return the result.
I tried this, but it doesn't work.
let Subset (dict:Dictionary<'T,'U>) (sub_list:list<'T>) =
let z = dict.Clear
sub_list |> List.filter (fun k -> dict.ContainsKey k)
|> List.map (fun k -> (k, dict.TryGetValue k) )
|> List.iter (fun s -> z.Add s)
|> List.iter (fun s -> z.Add s);;
--------------------------------------^^^
stdin(597,39): error FS0039: The field, constructor or member 'Add' is not defined
Perhaps there is a native function in F# to do that ?
thanks
EDIT
thanks to #TheInnerLight for his answer below
can you just educate me a bit more, and tell me how i should adapt that function if i want to return the original variable being modified ?
(of course it would be possible to go from where we call that function, call it with a temp variable, and reassign)
You have written:
let z = dict.Clear
z is of type unit->unit yet you are calling z.Add.
I suspect you want to write
let subset (dict:Dictionary<'T,'U>) (sub_list:list<'T>) =
let z = Dictionary<'T,'U>() // create new empty dictionary
sub_list |> List.filter (fun k -> dict.ContainsKey k)
|> List.map (fun k -> (k, dict.[k]) )
|> List.iter (fun s -> z.Add s)
z
TryGetValue is going to return something of type bool*'U in F#, which I suspect you don't want if already filtering by ContainsKey so you probably want to look up directly with dict.[k].
Note that Dictionary is a mutable collection so if you were to actually call dict.Clear(), it wouldn't return a new empty dictionary, it would mutate the existing one by clearing all elements. The immutable F# data structure usually used for key-value relationships is Map, see https://msdn.microsoft.com/en-us/library/ee353880.aspx for things you can do with Map.
Here is a map version (this is the solution I recommend):
let subset map subList =
subList
|> List.choose (fun k -> Option.map (fun v -> k,v) (Map.tryFind k map))
|> Map.ofList
Edit (in response to the question edit about modifying the input variable):
It's possible to update an existing dictionary using the destructive update operator <- on a mutable variable.
Option 1:
let mutable dict = Dictionary<Key,Value>() // replace this with initial dictionary
let lst = [] // list to check against
dict <- sublist dict lst
Likewise, my first function could be changed to perform only a side effect (removing unwanted elements).
Option 2:
let subset (d : System.Collections.Generic.Dictionary<'T,'U>) (sub_list : list<'T>) =
sub_list
|> List.filter (d.ContainsKey >> not)
|> List.iter (d.Remove >> ignore)
For an F# beginner I don't really recommend Option 1 and I really don't recommend Option 2.
The functional approach is to favour immutable values, pure functions, etc. This means you will be better off thinking of your functions as defining data transformations rather than as defining a list of instructions to be performed.
Because F# is a multi-paradigm language, it's easy to fall back on the imperative in the early stages but you will probably gain the most from learning your new language if you force yourself to adopt the standard paradigm and idioms of that language even if those idioms feel strange and uncomfortable to begin with.
The immutable data structures like Map and list are pretty efficient at sharing data as well as providing good time complexity so these are really the go-to collections when working in F#.

Erlang syntax for nested function with if

I've been looking around and can't find examples of this and all of my syntax wrestling skills are failing me. Can someone please tell me how to make this compile?? My ,s ;s or .s are just wrong I guess for defining a nested function...
I'm aware there is a function for doing string replaces already so I don't need to implement this, but I'm playing with Erlang trying to pick it up so I'm hand spinning some of the basics I need to use..
replace(Whole,Old,New) ->
OldLen = length(Old),
ReplaceInit = fun(Next, NewWhole) ->
if
lists:prefix(Old, [Next|NewWhole]) -> {_,Rest} = lists:split(OldLen-1, NewWhole), New ++ Rest;
true -> [Next|NewWhole]
end,
lists:foldr(ReplaceInit, [], Whole).
Basically I'm trying to write this haskell (also probably bad but beyond the point):
repl xs ys zs =
foldr replaceInit [] xs
where
ylen = length ys
replaceInit y newxs
| take ylen (y:newxs) == ys = zs ++ drop (ylen-1) newxs
| otherwise = y:newxs
The main problem is that in an if you are only allowed to use guards as tests. Guards are very restricted and, amongst other things, calls to general Erlang functions are not allowed. Irrespective of whether they are part of the OTP release or written by you. The best solution for your function is to use case instead of if. For example:
replace(Whole,Old,New) ->
OldLen = length(Old),
ReplaceInit = fun (Next, NewWhole) ->
case lists:prefix(Old, [Next|NewWhole]) of
true ->
{_,Rest} = lists:split(OldLen-1, NewWhole),
New ++ Rest;
false -> [Next|NewWhole]
end
end,
lists:foldr(ReplaceInit, [], Whole).
Because of this if is not used that often in Erlang. See about if and about guards in the Erlang documentation.

Does "Value Restriction" practically mean that there is no higher order functional programming?

Does "Value Restriction" practically mean that there is no higher order functional programming?
I have a problem that each time I try to do a bit of HOP I get caught by a VR error. Example:
let simple (s:string)= fun rq->1
let oops= simple ""
type 'a SimpleType= F of (int ->'a-> 'a)
let get a = F(fun req -> id)
let oops2= get ""
and I would like to know whether it is a problem of a prticular implementation of VR or it is a general problem that has no solution in a mutable type-infered language that doesn't include mutation in the type system.
Does “Value Restriction” mean that there is no higher order functional programming?
Absolutely not! The value restriction barely interferes with higher-order functional programming at all. What it does do is restrict some applications of polymorphic functions—not higher-order functions—at top level.
Let's look at your example.
Your problem is that oops and oops2 are both the identity function and have type forall 'a . 'a -> 'a. In other words each is a polymorphic value. But the right-hand side is not a so-called "syntactic value"; it is a function application. (A function application is not allowed to return a polymorphic value because if it were, you could construct a hacky function using mutable references and lists that would subvert the type system; that is, you could write a terminating function type type forall 'a 'b . 'a -> 'b.
Luckily in almost all practical cases, the polymorphic value in question is a function, and you can define it by eta-expanding:
let oops x = simple "" x
This idiom looks like it has some run-time cost, but depending on the inliner and optimizer, that can be got rid of by the compiler—it's just the poor typechecker that is having trouble.
The oops2 example is more troublesome because you have to pack and unpack the value constructor:
let oops2 = F(fun x -> let F f = get "" in f x)
This is quite a but more tedious, but the anonymous function fun x -> ... is a syntactic value, and F is a datatype constructor, and a constructor applied to a syntactic value is also a syntactic value, and Bob's your uncle. The packing and unpacking of F is all going to be compiled into the identity function, so oops2 is going to compile into exactly the same machine code as oops.
Things are even nastier when you want a run-time computation to return a polymorphic value like None or []. As hinted at by Nathan Sanders, you can run afoul of the value restriction with an expression as simple as rev []:
Standard ML of New Jersey v110.67 [built: Sun Oct 19 17:18:14 2008]
- val l = rev [];
stdIn:1.5-1.15 Warning: type vars not generalized because of
value restriction are instantiated to dummy types (X1,X2,...)
val l = [] : ?.X1 list
-
Nothing higher-order there! And yet the value restriction applies.
In practice the value restriction presents no barrier to the definition and use of higher-order functions; you just eta-expand.
I didn't know the details of the value restriction, so I searched and found this article. Here is the relevant part:
Obviously, we aren't going to write the expression rev [] in a program, so it doesn't particularly matter that it isn't polymorphic. But what if we create a function using a function call? With curried functions, we do this all the time:
- val revlists = map rev;
Here revlists should be polymorphic, but the value restriction messes us up:
- val revlists = map rev;
stdIn:32.1-32.23 Warning: type vars not generalized because of
value restriction are instantiated to dummy types (X1,X2,...)
val revlists = fn : ?.X1 list list -> ?.X1 list list
Fortunately, there is a simple trick that we can use to make revlists polymorphic. We can replace the definition of revlists with
- val revlists = (fn xs => map rev xs);
val revlists = fn : 'a list list -> 'a list list
and now everything works just fine, since (fn xs => map rev xs) is a syntactic value.
(Equivalently, we could have used the more common fun syntax:
- fun revlists xs = map rev xs;
val revlists = fn : 'a list list -> 'a list list
with the same result.) In the literature, the trick of replacing a function-valued expression e with (fn x => e x) is known as eta expansion. It has been found empirically that eta expansion usually suffices for dealing with the value restriction.
To summarise, it doesn't look like higher-order programming is restricted so much as point-free programming. This might explain some of the trouble I have when translating Haskell code to F#.
Edit: Specifically, here's how to fix your first example:
let simple (s:string)= fun rq->1
let oops= (fun x -> simple "" x) (* eta-expand oops *)
type 'a SimpleType= F of (int ->'a-> 'a)
let get a = F(fun req -> id)
let oops2= get ""
I haven't figured out the second one yet because the type constructor is getting in the way.
Here is the answer to this question in the context of F#.
To summarize, in F# passing a type argument to a generic (=polymorphic) function is a run-time operation, so it is actually type-safe to generalize (as in, you will not crash at runtime). The behaviour of thusly generalized value can be surprising though.
For this particular example in F#, one can recover generalization with a type annotation and an explicit type parameter:
type 'a SimpleType= F of (int ->'a-> 'a)
let get a = F(fun req -> id)
let oops2<'T> : 'T SimpleType = get ""

Resources