Hello, Juliet.

1.\ There is nice paper by Peter Norvig: Design patterns in Dynamic Programming

2.\ Many design patterns (DP) are created to minimize errors at desing phase of software creation. For OO world those errors and troubles commonly linked to objects state, identity and class decomposition. In fact, OO designer ought to solve two tasks at one time: algorithmic decomposition and state/hierarchy decomposition.
For FP world you can solve those tasks independently. So, much of classic GoF DP are not so nice for FP world. Of course, you can train your sense of FP style by reading F#/Ocaml books and code snippets.

3.\ If you want to quickly destabilize your point of view to DP, i can recommend to find Haskell tutorial with clear description of the type classes, class exemplars and related Prelude parts (i don't remember concrete one, but www.haskell.org contains page with links to many nice tutorials).

By on 7/10/2008 12:21 PM ()

Hi Juliet,

You are now asking the correct questions!

There are certainly many patterns encountered in functional programming but nobody has really tried to collate them into a single set of design patterns. Consequently, they are not referred to as <i>design patterns<i>. Also, much of the literature on this predates the relatively recent invention of "design patterns" in OOP. The article that you cited which states that OO design patterns are obsolete in functional languages does have a strong point though. Most so-called "design patterns" are nothing more than work arounds for the deficiencies of OOP. Many of those deficiencies are simply not present with functional programming and, consequently, the work arounds are no longer of value. However, there are a precious few genuinely paradigm-agnostic design patterns (such as model-view-controller) that do persist with functional programming. Although the literature on functional programming rarely describes "design patterns" this is largely because they are not explicitly recognised and named as such. I would say that there are many well known functional design patterns: <UL><li>Using accumulator arguments when converting functions into tail recursive form.</LI><li>Continuation passing style.</LI><li>Combinators and, in particular, parser combinators.</LI><li>Untying the recursive knot via parameterization.</LI><li>Unfold.</LI><li>...</LI></UL> Both my (unpublished) book <A href="http://www.ffconsultancy.com/products/fsharp_for_scientists/?hub">F# for Scientists</A> and our <A href="http://www.ffconsultancy.com/products/fsharp_journal/?hub">F#.NET Journal</A> articles have already addressed functional design patterns specifically in F#. The recent article <A href="http://ocamlnews.blogspot.com/2008/06/tricks-with-recursion-knots-modules-and.html">Tricks with recursion: knots, modules and polymorphism</A> from our <A href="http://www.ffconsultancy.com/products/ocaml_journal/?hub">OCaml Journal</A> may also be of interest. Regarding your particular code here, I think the answers to your questions should be obvious. You have a class that implements an interface that defines a single function. That is nothing more than a reinvention of a closure from functional programming. So forget about all of that and just pass a function around. You ask what happens when RealProcess gets more complicated and the answer is that nothing changes because (as you decreed) your processor is still necessarily represented entirely by a single function. This is often true and is precisely why functional programming is so constructive (excuse the hillarious pun). There are situations where ML-style functional and object oriented programming have different characteristics and you must learn when to choose between them (or use a mixture of both, if necessary). The advantage of F# is that you have both completely at your disposal. This should lead you onto an obvious next question: for what applications is F# most useful? Cheers, Jon Harrop.

By on 7/7/2008 6:11 PM ()

Hi Julient,

Functional languages allow you to "capture design patterns" as functions, that is commonly repeated bits of code can rewritten as one function just leaving wholes where ever a bit of code is different. For example the gang of four's iterator pattern is simply a List.iter function in F#. In FP we generally call this abstraction of control flow and I wrote a blog post about this a little while ago: [link:www.strangelights.com]

Higher level design patterns like depency injection are still important and .NET has serval different depenancy injection containers, most of which are liberally inspired by java depency injection containers, all of which can be used with F#. Just google for spring .NET or castle project for more information on this.

Cheers,
Rob

By on 7/7/2008 12:43 AM ()

Hi Juliet,

You are iterating towards good F# design, which is usually a mix of FP and OO. You should also feel free to use your existing OO patterns, many of which are highly applicable to F# and indeed "look lovely" when captured in idomatic F#. My recommendation as people learn F# is to "change one variable at a time": you're learning a new language, so it's OK to keep your existing design patterns and gradually learn how they may simplify.

An object as simple as IProcess would typically be modelled as a function

1
2
3
4
 

type Processor = (TransactionItem -> unit) 

You wouldn't need to change this just because any particular Process does something complex. For mocking it does indeed look like you're just switching your code to a simpler processing function

1
2
3
4
5
6
7
8
 

let RealProcessor(item:TransactionItem) = <lots of code>

let MockProcessor (item: TransactionItem) = item.Processed <- true

let Processor = if testing then MockProcessor else RealProcessor

If the actual behaviour of individual processing functions changes when mocking then just pass the mocking flag in as a parameter:

1
2
3
4
 

type Processor = (bool * TransactionItem -> unit) 

So, when should you use objects richer than functions? Very often. You would typically switch to using an interface when your notion of a "Processor" becomes more complex. For example it might

  • report partial progress by raising an event (though that could equally be modelled by passing the event to trigger in as a parameter)
  • it might support cancellation (though in this case you could also change the return type "unit" to be an ICancallable object)
  • etc.
By on 7/7/2008 7:25 AM ()
IntelliFactory Offices Copyright (c) 2011-2012 IntelliFactory. All rights reserved.
Home | Products | Consulting | Trainings | Blogs | Jobs | Contact Us | Terms of Use | Privacy Policy | Cookie Policy
Built with WebSharper