posted by contextfree

]]>C

posted by Charles

]]>posted by exoteric

]]>

What an awesome idea! ... I'm surprised Eric has time to do this ... but glad he did!!! What a service for the .Net dev community! I have friends (and me too!) who've bought books about functional programming and have not been able to get through them. This however, is just what is needed!!! FP is obviously a big deal and growing in importance .... mullticore, languages like Scala, FSharp and even CSharp.

There's a ton of other guest lecturers I would like to hear .... Andrew Kennedy, Simon Peyton Jones, Don Syme ... I'd love to hear Joe Duffy talk about using FP to enable Paralell Extensions for .Net!! The mind boggles ...

Thanks MS, thanks Charles and thanks Eric!!

PS: One request ... I havent listened to the recording yet ... however, it would be great if some of the examples were done in FSharp (rather than Haskell) only because quite a few of us are likely to actually use FSharp for work at some point and I doubt many folks are gonna use Haskell for any real work anytime soon ... just my 02 cents.

posted by keithfl

]]>posted by exoteric

]]>

Language syntax is just an abstraction of fundamental concepts. Haskell is the right choice here and your increase in functional knowledge will be directly applicalble to programming in F# (or any other functional language).

C

posted by Charles

]]>

Speaking of object-orientation, I remember several years ago Java and similar languages being presented as higher-order typed languages (**HOT**), meaning functions (methods) in these languages were also higher-order because one can pass in
objects and these objects can contain other functions (methods) and so in practice one almost ends up with the same "effect". Of course then we have all the dirty side-effects of mutating objects passed into other objects, unless the objects themselves come
from classes that are defined as immutable; in a way immutable objects are still-born: after construction they are immutable and become lifeless - and when stopped being used anymore the holy garbage collecter carries the object identity into oblivion.

One question: would you say this sums up (one of) the selling point of purity and laziness: laziness without purity is
**dangerous** (unpredictable side-effects) whilst purity without laziness is
**slow** (repeated evaluation). It's like "bounded computations" you may not know what's in the box (it's black or your vision is) but you can be sure that whatever is in the box does not escape it (not through the front door (the argument list);
nor through the backdoor (the return value)). In effect a prison for sinful computation. Another selling point being compositionality.

And on expressions vs statements. One thing I seriously miss in C# is having expressions everywhere; for example
**if** is an expression and a **{}** block is an expression, evaluating to the last expression in the block. To get around this one can use the
**e?a:b** expression pattern. Same for switches. Erik showed "iteration" in Haskell using list comprehension (I believe). In C#, I'd use
**Enumerable.Range(i,n)**. It's a more disciplined approach but if discipline is all you have, it'll come natural.

Appropos "weird" encodings of pure functions.

(PS - The triangular operator mentioned is the forward pipe operator **|>**; love that, as well as the
**>>** right composition operator.)

posted by exoteric

]]>posted by Bass

]]>C

posted by Charles

]]>posted by tomkirbygreen

]]>posted by Bas

]]>

Of course, since this is Erik Meijer, he will modify things as he sees fit (and he is certainly qualified to do so - Graham is a peer of Erik's, after all).

C

posted by Charles

]]>

Thanks Professor! As I told Charles previously, it was watching some of your initial vids on functional programming as well as Brian Beckman's series that got me into learning Haskell. I do enjoy it and wished that F# had some
*more* of the features that Haskell does. I will make a post about it as I would like your POV on the matter. Thanks again, looking forward to the rest of the series.

~sparky

[http://sdasrath.blogspot.com/]

posted by wil2300

]]>

Some other videos do have sound.

posted by ivan_

]]>C

posted by Charles

]]>You should check out Nemerle if feels very much like C#, but with everything (within a method) being an expression.

posted by Andrew Davey

]]>posted by jolson88

]]>posted by PerfectPhase

]]>

One comment - though you are focusing on Haskell, please keep it tied to C# (e.g., "here's how to do it in C#") and keep it practical. By comign back to C#, unfamiliar concepts look familiar. By keeping it practical, we'll see how this stuff can really be used. Haskell - not just for Fibonacci anymore! OK that's a bit facetious.

As for the homework, here is my solution. I basically transcribed the Haskell version shown. I am sure it can be prettier:

public static IEnumerable<A> QuickSort<A>(IEnumerable<A> vals)

where A : IComparable<A>

{

if (vals.Skip(1).IsEmpty())

return vals;

else

{

A pivot = vals.First();

var rest = vals.Skip(1);

var left = from x in rest

where x.CompareTo(pivot) <= 0

select x;

var right = from x in rest

where x.CompareTo(pivot) > 0

select x;

return QuickSort(left).Concat(vals.Take(1)).Concat(right);

}

}

Note : IsEmpty is an extension method which tests if a sequence is empty. I can't believ that is not already defiend in the framework so I am sure i missed it.

I particularly like the end part, where I concatenate the single pivot value into the sequence:

return QuickSort(left).Concat(vals.Take(1)).Concat(right);

Since the list is not empty, I know I can take the first value and stick in the right place. My base case also takes advantage here:

if (vals.Skip(1).IsEmpty())

return vals;

else

...

If the sequence given only has one element, I just return it unchanged and it automatically goes in the right spot. Thank you recursion!

Full source code & VS2008 project available on github.

Justin

posted by Justin Bailey

]]>posted by jolson88

]]>C

posted by Charles

]]>posted by wil2300

]]>C

posted by Charles

]]>

//Not recomended if the list is big. Lists on F# are not lazy. ys and zs would be computed on the spot.

//Also, the last statement would blow the stack if the list is too big.

let rec QS = function

| [] -> []

| x::xs ->

let ys = xs |> List.filter((>=) x)

let zs = xs |> List.filter((<) x)

QS ys @ [x] @ QS zs

//Using F# sequences. The equivalent of Haskell lists

let rec QSLazy = function

| Empty -> Seq.empty

| Seq (x,xs) ->

let ys = xs |> Seq.filter((>=) x)

let zs = xs |> Seq.filter((<) x)

Seq.append (QSLazy ys) (Seq.append (seq {yield x}) (QSLazy zs))

//Active Pattern to make pattern matching over F# sequences. Needed to make it look more like the haskell solution

and (|Empty|Seq|) xs =

if xs |> Seq.isEmpty then

Empty

else

let x = xs |> Seq.hd

let xs = xs |> Seq.skip 1 |> Seq.cache

Seq (x,xs)

Nice lecture. I'm looking forward to the next one.

posted by paks8150

]]>Thank's a lot for your generosity in being so generous with sharing your knowledge£!

posted by HansSchenker

]]>posted by exoteric

]]>

around 18:30 min, Erik starts to talk about Dave Turner's language SASL. For those interested in the mechanics of compiling SASL into the SKI combinators mentioned by Erik, I have written a tutorial on how to write a functioning SASL compiler (complete from front-end to back-end). Most of it is based on Dave Turner's original notes on SASL.

Available here: The Construction of an SASL Compiler. The SKI-specific material starts with Section 3.3 (page 19).

(This has always been among the courses my students enjoyed the most — by far.)

Enjoy, and thanks for these lectures, Erik!

—Torsten

posted by TorstenGrust

]]>this stuff really applies to everyone, regardless of language preference.

posted by aL_

]]>posted by gamefm

]]>

Distributed the link to my collegues as a must see,..

Nice shirt again Erik

posted by Maddus Mattus

]]>static IEnumerable<T> QuickSort<T>(IEnumerable<T> enumerable) where T : IComparable<T> { var ps = enumerable.Take(1); var pt = from pivot in ps from x in enumerable.Skip(1) group x by 0 < x.CompareTo(pivot); var lt = pt.Where(g => !g.Key).SelectMany(g => QuickSort(g)); var gt = pt.Where(g => g.Key).SelectMany(g => QuickSort(g)); return lt.Concat(ps).Concat(gt); }

posted by simon.buchan

]]>

The presenter in that video is confused by "first class functions" and "higher order functions". He combines the two into "first order functions" which is the opposite of what he meant to say.

posted by Jules.dot

]]>posted by tomkirbygreen

]]>

posted by Pop Catalin Sever

]]>

2 machines, xp sp3, sl3, ie8 -- no audio

Vista home 64, ie8, sl3 -- works fine

And, thank you all for the great job you do educating the mere mortals!

posted by was

]]>

David Roh

posted by davidjjon

]]>

Thinking about type-inference and intellisense. An annoying aspect of the C-style adopted by C# is that when you supply type-parameters that are used in the return type, intellisense gets in the way and becomes a nuisance - really not its fault, it's just the way it things are defined.

e.g. Instead of this,

IEnumerable<T> foo<T>(IEnumerable<T> xs) ...

adopt this

foo<T>(x: IEnumerable<T>): IEnumerable<T> ...

and in a pure signature, why would you even care that much about parameter names

foo :: IEnumerable<T> -> IEnumerable<T>

Then you can always argue about whether using "a sequence" is better than "sequence<a>"; leaning towards the later.

First attempt at the exercise

public static IEnumerable<T> Qsort1<T>(this IEnumerable<T> s) where T : IComparable<T> { var ss = from x in s.Take(1) let xs = s.Skip(1) let a = xs.Where(y => y.CompareTo(x) <= 0).Qsort1() let b = xs.Where(y => y.CompareTo(x) > 0).Qsort1() select a.Concat(s.Take(1)).Concat(b); return ss.Any() ? ss.First() : Enumerable.Empty<T>(); }

The lack of pattern matching is quite annoying here. And also "Any" leans you towards the defined case first, whereas the null case should really come first as it's the simplest. And last, it's annoying that you have to specify a partition using two criteria; really you'd want to have one selector create a partition. So that's next.

posted by exoteric

]]>C

posted by Charles

]]>

WMV works fine.

The weird thing is, all the other SL videos are fine. It is just this video that has no audio.

B

posted by bradspencer

]]>posted by cain06

]]>C

posted by Charles

]]>C

posted by Charles

]]>C

posted by Charles

]]>

I think my only suggestion would be to check if s is empty first, then you can rewrite:

public static IEnumerable<T> Qsort1<T>(this IEnumerable<T> s) where T : IComparable<T>

{

return ! s.Any() ? Enumerable.Empty<T>() :

from x in s.Take(1)

let xs = s.Skip(1)

let a = xs.Where(y => y.CompareTo(x) <= 0).Qsort1()

let b = xs.Where(y => y.CompareTo(x) > 0).Qsort1()

select a.Concat(s.Take(1)).Concat(b);

}

But I don't know if that is allowed syntax.

posted by Justin Bailey

]]>Very very great! Looking forward to see the next chapters!

Thanks to Channel9 and to my professor !

posted by MarioTP

]]>

http://channel9.msdn.com/posts/Duncanma/Testing-the-Audio-issue-with-XP/

posted by Duncanma

]]>

Another 'no audio in Silverlight' from me. As requested, here is the information:

Silverlight version: 3.0.40818.0

Browser version: Both Google Chrome v3.0.195.24 and IE v7.0.5730.11

OS: Windows XP SP2 (32-bit, Version 5.1 (Build 2600.xpsp_sp2_qfe.090206-1239 : Service Pack 2))

posted by vcomrhencke

]]>

public static IEnumerable<T> Qsort1<T>(this IEnumerable<T> s) where T : IComparable<T> { return !s.Any() ? Enumerable.Empty<T>() : (from x in s.Take(1) let xs = s.Skip(1) let a = xs.Where(y => y.CompareTo(x) <= 0).Qsort1() let b = xs.Where(y => y.CompareTo(x) > 0).Qsort1() select a.Concat(s.Take(1)).Concat(b)).First(); }

I think we should (maybe) use the Maybe monad here

posted by exoteric

]]>posted by vcomrhencke

]]>

http://channel9.msdn.com/posts/Duncanma/Testing-the-Audio-issue-with-XP/

That video (audio) works fine on my machine.

I do have SL3, I earlier said SL2, sorry.

So again my platform Win XP SP3 SL3 IE8 or FF

Thanks.

posted by ivan_

]]>http://channel9.msdn.com/posts/Duncanma/Testing-the-Audio-issue-with-XP/

That should work on your system, which means we have isoloated and corrected the issue. Unfortunately, the solution will require that we re-encode a bunch of videos. So, in the meantime, please watch in Windows Movie Maker for a little while longer.

C

posted by Charles

]]>posted by prujohn

]]>posted by Craig Stuntz

]]>Public Function QuickSort(Of T As IComparable)(ByVal x As IEnumerable(Of T)) As IEnumerable(Of T) Return If(x.Count < 2, x, QuickSort( _ x.Where(New Func(Of T, Boolean)(Function(xn2 As T) xn2.CompareTo(x.ElementAt(x.Count \ 2)) < 0))).Union( _ x.Where(New Func(Of T, Boolean)(Function(xn2 As T) xn2.CompareTo(x.ElementAt(x.Count \ 2)) = 0))).Union( _ QuickSort(x.Where(New Func(Of T, Boolean)(Function(xn3 As T) xn3.CompareTo(x.ElementAt(x.Count \ 2)) > 0))))) End Function

posted by AdamSpeight2008

]]>

public static IEnumerable<T> QuickSort<T>(this IEnumerable<T> input) where T : IComparable<T> { var first = input.FirstOrDefault(); var result = (from current in input.Skip(1) group current by first.CompareTo(current) > 0 into grouping select grouping).GroupIntoBool(); return !input.Any() ? Enumerable.Empty<T>() : result[false].QuickSort().Concat(input.Take(1)).Concat(result[true].QuickSort()); } public static Dictionary<bool,IEnumerable<T>> GroupIntoBool<T>(this IEnumerable<IGrouping<bool,T>> input) { return (from bools in new List<bool>() { true, false } join grouping in input on bools equals grouping.Key into joinedgroup select new { val = bools, rest = joinedgroup.FirstOrDefault() ?? Enumerable.Empty<T>() }).ToDictionary(a => a.val, a => a.rest); }

posted by cdwatkins

]]>posted by simon.buchan

]]>Dim CompareValues() As Integer= {-1, 0, 1} Public Function QuickSort(Of T As IComparable(Of T))(ByVal input As IEnumerable(Of T)) As IEnumerable(Of T) Dim result = (From cv As Integer In CompareValues _ Group Join iv As T In input _ On iv.CompareTo(input(0)) Equals cv _ Into Group _ Select Group) Return If(input.Count < 2, _ input, _ QuickSort(result(0)) _ .Concat(result(1)) _ .Concat( _ QuickSort(result(2)) _ ) _ ) End Function

Just wish i could get rid of the if statement.

posted by AdamSpeight2008

]]>posted by tomkirbygreen

]]>

Next in line -

public static IEnumerable<T> Flatten<T>(this IEnumerable<IEnumerable<T>> xs) { return xs.SelectMany(x => x); } public static IEnumerable<T> Qsort<T>(this IEnumerable<T> s) where T : IComparable<T> { return (from x in s.Take(1) let xs = s.Skip(1) let a = xs.Where(y => y.CompareTo(x) <= 0).Qsort() let b = xs.Where(y => y.CompareTo(x) > 0).Qsort() select a.Concat(s.Take(1)).Concat(b)).Flatten(); }

Looks like flatten is a "recursive" monadic bind. Still, much less elegant than the Haskell definition.

And now doing away with the horrible IComparable noise that obfuscates the code

public static IEnumerable<int> QiSort(this IEnumerable<int> s) { var Qi = from z in s.Take(1) let xs = s.Skip(1) let p = from x in xs where x ≤ z select x let q = from x in xs where x > z select x select p.QiSort().Concat(s.Take(1)).Concat(q.QiSort()); return Qi.Flatten(); }

posted by exoteric

]]>posted by Zathros

]]>

Our experiment = successful!

Cheers,

C

posted by Charles

]]>posted by ACG

]]>

C

posted by Charles

]]>public struct Pair<A, B> { public A First { get; set; } public B Second { get; set; } }

Then a few extension methods:

public static Pair<IEnumerable<T>,IEnumerable<T>> Partitions<T>(this IEnumerable<T> xs, Func<T, bool> p) { var partitions = (from x in xs group x by p(x) into g select g).ToDictionary(g => g.Key); return new Pair<IEnumerable<T>,IEnumerable<T>>() { First = partitions.ContainsKey(true) ? partitions[true].AsEnumerable() : Enumerable.Empty<T>(), Second = partitions.ContainsKey(false) ? partitions[false].AsEnumerable() : Enumerable.Empty<T>() }; } public static bool IsNil<T>(this IEnumerable<T> xs) { return !xs.GetEnumerator().MoveNext(); } public static bool LessThan<T>(this T x, T y) where T : IComparable<T> { return x.CompareTo(y) < 0; }

Finally, QSort itself:

public static IEnumerable<T> QSort<T>(this IEnumerable<T> xs) where T : IComparable<T> { if (xs.IsNil()) return Enumerable.Empty<T>(); else { var pivot = xs.First(); var p = xs.Skip(1).Partitions(y => y.LessThan(pivot)); var smaller = p.First; var larger = p.Second; return smaller.QSort() .Concat(new List<T>{pivot}) .Concat(larger.QSort()); } }

**Edit**: I was bored and also wrote a Python version...

def partition(xs, p): z = ([],[]) for x in xs: z[1-bool(p(x))].append(x) return z # Note that partition is not quite functional, as it uses mutation. # The mutation, however, only affects local values. The function # partition for the outside world is referential transparent. def qsort(xs): if not xs: return [] else: pivot = xs[0] smaller, larger = partition(xs[1:], lambda x: x < pivot) return qsort(smaller) + [pivot] + qsort(larger)

posted by ShinNoNoir

]]>

Just wanted to let you know that your link did the trick; that video plays sound as expected.

Thanks!

posted by vcomrhencke

]]>

posted by ryanb

]]>*And that’s kinda beautifull*

Thank you so much !

posted by PatB

]]>

C

posted by Charles

]]>

What's really surprising is the power of combinators. I didnt know that one of them would suffice. Could somebody show a small example of this powerful deduction?

posted by kunjaan

]]>

First, GHCi

Next, WinGHCi

Then, concept denotation

And a small reference

posted by exoteric

]]>(never mind, i found out the new way -- click on the alternative formats and get the media player or what not)

posted by brianbec

]]>F#:

#light

open System

open System.Threading

open Microsoft.FSharp.Control

// create a random list

let maxSize=4

let rand = new Random()

let list=[ for i in 1..maxSize do yield rand.Next(100*maxSize)]

printfn "%A" list

//1. Simple version

// 'a list -> 'a list

let rec simpleQuickSort(inL)=

match inL with

| []->[]

| h::t->List.partition(fun e->e<=h) t|>fun(l,r)->simpleQuickSort(l)@ h::simpleQuickSort(r)

let sL=simpleQuickSort(list)

printfn "%A" sL

Erlang :

-module(parallelquicksort).

-export([gen_randomlist/2,simplesort/1]).

%% generates a list of random numbers

gen_randomlist(N,MaxNumber)->

lists:map(fun(_)->random:uniform(MaxNumber) end,lists:seq(1,N)).

%% simple version

simplesort([])->[];

simplesort([H|Tail])->simplesort([X||X<-Tail,X<H])

++++

simplesort([X||X<-Tail,X>=H]).

F# :

////2 ASynchronous version

// create asynchronous task for list partition

//'a list * ('a -> bool) -> Async<'a list>

// f is function for partition

let asyncPartition(l,f)= async{ return l|>List.filter(f)}

let rec asyncQuickSort(inL)=

match inL with

|[]->[]

|h::t-> let asynTasks=[asyncPartition(t,fun(x)->x<=h);asyncPartition(t,fun(x)->x>h)]

let asynResult=Async.Run(Async.Parallel asynTasks)// execute

- asyncQuickSort(asynResult.[0])@h::asyncQuickSort(asynResult.[1])//join

let asynSortedList=asyncQuickSort(list)

printfn "%A" asynSortedList

F#:

//3. Message Passing Style Version

type MsgListPartition = | GetList of int list*(int->bool)*AsyncReplyChannel<int list>

| Stop

type PartitionServer(srvName:string)=

let receiver = MailboxProcessor<MsgListPartition>.Start(fun inbox->

let rec loop() =

async {

let! msg=inbox.Receive()

match msg with

|Stop->return()

|GetList(l,f,rep)-> let p =l|>List.filter(f)

rep.Reply(p)

return! loop()

}

loop())

member o.Stop() = receiver.Post(Stop)

member o.GetList(l,f)=receiver.AsyncPostAndReply(fun aS->GetList(l,f,aS))

let s1Server = new PartitionServer("Server-l")

let s2Server = new PartitionServer("Server-r")

let rec mpsQuickSort(inL)=

match inL with

|[]->[]

|h::t-> let asynL=[s1Server.GetList(t,fun(x)->x<=h);s2Server.GetList(t,fun(x)->x>h)]

let asynResult=Async.Run(Async.Parallel asynL)

mpsQuickSort(asynResult.[0])@h::mpsQuickSort(asynResult.[1])

let z=mpsQuickSort(list)

printfn "%A" z

Erlang:

%% parallelversion

left_sort()->

receive

{From,Pivot,List} -> From ! {self(),[X||X<-List,X<Pivot]}

end.

right_sort()->

receive

{From,Pivot,List} -> From ! {self(),[X||X<-List,X>=Pivot]}

end.

gather(SPId) ->

receive

{SPId, Ret} -> Ret

end.

psort([])->[];

psort()->;

psort([H|Tail])-> [LPId,RPId]=[spawn(fun left_sort/0),spawn(fun right_sort/0)],

LPId! RPId! {self(),H,Tail},

psort(gather(LPId))++++psort(gather(RPId)).

posted by Paul555

]]>posted by DOppenheimer

]]>f (x:xs) = f ys ++ [x] ++ f zs

If you're working with IEnumerable<IComparable> as your lists, what's the preferred C# w LINQ mapping for the right-hand side of this?

posted by larryobrien

]]>

If you want to be fancy, you could imitate LINQ to XML's Add method on XElement and can create a version of Concat that takes a params[] of object (http://msdn.microsoft.com/en-us/library/system.xml.linq.xelement.add.aspx) and write Enumerable.Concat(f(ys),x,f(zs)). But you run the risk that the static typing police starts chasing you

posted by head.in.the.box

]]>posted by aemami99

]]>posted by drozzy

]]>posted by stej

]]>posted by bwal

]]>

Thanks.

posted by pdcjlw1

]]>Futhermore, if "i know", why are you telling me this?

Just a suggestion

posted by Wiep Corbier

]]>posted by peoples

]]>

Much regards. Good day!

posted by lambdaf

]]>It's a great chance to become a student of Professor Erik.

I always wanna learn a pure functional programming language.

What a great chance fore me!

Thanks much.

posted by nyinyithann

]]>

The following is my ugly and stupid attempt to the homework.

class Program { delegate IEnumerable<T> QSortFunc<T> (IEnumerable<T> source) where T: IComparable<T>; static void Main(string[] args) { QSortFunc<int> qsort = null; qsort = nums => nums.Count() < 1 ? Enumerable.Empty<int>() : qsort(nums.Where(num => num.CompareTo(nums.FirstOrDefault()) <= 0).Skip(1)) .Concat(nums.Take(1)) .Concat(qsort(nums.Where(num => num.CompareTo(nums.FirstOrDefault()) > 0))); var seq = new[] { 1, 1, 2, 9, 7, 8, 3, 9, 7, 8, 3, 0, -1 }; var result = qsort(seq); result.ToList().ForEach(Console.WriteLine); } }

posted by nyinyithann

]]>

Jeroen Fokker, **The Systematic Construction of a One-combinator Basis for Lambda-Terms**.*Formal Aspects of Computing* **4** (1992), pp. 776-780.

http://people.cs.uu.nl/jeroen/article/combinat/index.html

posted by MattR

]]>

#!/usr/bin/perl sub qsort { my @array = @_; return () unless @array; my $pivot = shift @array; my @larger = (); my @smaller = (); map {$_ >= $pivot ? push @larger, $_ : push @smaller, $_} @array; return (qsort(@smaller), $pivot, qsort(@larger)); }

The question i have about the haskell version, when smaller and larger are constructed, does that walk the xs list twice to generate the two lists, or is it optimised to do it once?

posted by Todd Hunter

]]>posted by deadc0de

]]>

My solution to the Home work ...

//Find x(member of xs), such that the x is central value

void sort(int *array, int size) {

int count, lcount = 0, mcount = 0;

//To hold the smaller xs(than x)

int less[size - 1];

//To hold the larger xs(than x)

int more[size - 1];

for(count = 1; count < size; count++) {

//array[0] is the x

if(array[0] > array[count]) {

//The xs smaller than x

less[lcount] = array[count];

lcount++;

}

else if(array[0] <= array[count]) {

//The xs larger than x

more[mcount] = array[count];

mcount++;

}

}

//Put the x in the middle of the array

array[lcount] = array[0];

if(lcount)

for(count = 0; count < lcount; count++)

array[count] = less[count];

if(mcount)

for(count = 0; count < mcount; count++)

*(array + lcount + 1 + count) = more[count];

if(lcount > 1)

sort(array, lcount);

if(mcount > 1)

//array[lcount] is x

sort((array + lcount + 1), mcount);

}

Sohail Qayum Malik.

posted by Aeon

]]>