473,387 Members | 1,535 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,387 software developers and data experts.

Writing a simple function in C#


I am trying to learn C# and .NET programming in general but I am finding it
very hard going. To start with, I'd like to translate some trivial
functions from other languages that I am familiar with into C#.

Here is a simple function in OCaml that nests "n" applications of "f"
around "x", with "n" defaulting to "n=2":

let rec nest ?(n=2) f x = if n=0 then x else nest ~n:(n-1) f (f x)

For example, "nest f x" gives "f(f(x))" and "nest ~n:3 f x"
gives "f(f(f(x)))".

I am unable to write this elegantly in C#. This is the best I've come up
with and it doesn't even support partial application (currying):

class Program
{
abstract class Nest<T>
{
int n;

public Nest()
{
n = 2;
}

public abstract T f(T x);

public T Apply(T x)
{
while (n 0)
{
x = f(x);
--n;
}

return x;
}

public int N
{
get
{
return n;
}

set
{
n = value;
}
}
}

class NestTwice : Nest<int>
{
public override int f(int x)
{
return 2 * x;
}
}

static void Main(string[] args)
{
NestTwice nestTwice = new NestTwice();
nestTwice.N = 3;
System.Console.WriteLine(nestTwice.Apply(2));
}
}

So I've implemented the higher-order function "nest" as an abstract base
class "Nest" that you must derive from and override the "f" member
function. The optional argument "n" in the OCaml is implemented as a
mutable property "N" with its default value set to 2 by the constructor.

The "NestTwice" class derives from the "Nest" class, specialized to the
type "T=int", and implements the "f" member such that it doubles its
integer argument.

The main program then constructs an object of the class "NestTwice", sets
its property "N" to 3, overriding its default value of 2, and calls
the "Apply" method to compute the equivalent of "nest n f".

Needless to say, there are many aspects of this that I am not happy with!

1. Can the handling of the function argument "f" be written more elegantly
(but still generically) in terms of delegates? I'd like to replace my
C++-style abstract "Nest" class with something like:

public static T nest<T>(int n, Delegate<T, Tf, x) {
while (n>0) { x=f(x); --n; }
return x;
}

2. My handling of optional arguments is hideous. Can this be done without
mutation, i.e. without first setting the option to its default and then
altering it to the specified value?

3. Is there a simpler way of getting the return value of a function with
optional arguments than making up a "standard" member called "Apply" and
giving it the non-optional arguments after the optional ones have settled
to their true values?

4. Can the "Nest" class be derived from a statically-typed delegate class?

5. Did I miss something fundamental in C#: can any of this be written more
succinctly or elegantly in C#?

6. Are there any tools that can help by autogenerating code like this? Are
there any .NET languages that can do this as elegantly as OCaml?

My motivation is largely to write better F# code rather than C# but both
languages have the same implementation of optional arguments, so the F#
equivalent of the OCaml one-liner also entails a page of classes, mutation
etc.

--
Dr Jon D Harrop, Flying Frog Consultancy
The F#.NET Journal
http://www.ffconsultancy.com/product...ournal/?usenet
May 24 '07 #1
8 5494
Jon Harrop <jo*@ffconsultancy.comwrote:

<snip>

Rather than answer each of the questions in turn, here's how I'd
implement it:

delegate T Mutator<T>(T t);

static T Mutate<T>(Mutator<Tmutator, T initial, int times)
{
for (int i=0; i < times; i++)
{
initial = mutator(initial);
}
return initial;
}

static T Mutate<T>(Mutator<Tmutator, T initial)
{
return Mutate(mutator, initial, 2);
}

Points to note:
1) Use a generic delegate instead of overriding. Apart from
anything else, this makes life a lot simpler when anonymous methods
are available
2) There's no real need for a separate class with state
3) Use overloading to provide optional parameters
4) Use a for loop instead of while to be idiomatic
5) Boy is it shorter ;)
Your complete program (which doesn't use the default number of
iterations) becomes:

delegate T Mutator<T>(T t);

class Test
{
static T Mutate<T>(Mutator<Tmutator, T initial, int times)
{
for (int i=0; i < times; i++)
{
initial = mutator(initial);
}
return initial;
}

static void Main()
{
int result = Mutate(delegate(int x) { return x*2; }, 2, 3);
System.Console.WriteLine (result);
}
}

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet
If replying to the group, please do not mail me too
May 24 '07 #2
Something like:

namespace Foo

{

public partial class Foo : Form

{

public delegate T Funct<T>(T x);

private void startButton_Click(object sender, EventArgs e)

{

int s = apply(delegate(int x) { return x +5; },

1, 4);

}

public T apply<T>(Funct<Tfunct, T arg, uint timesApply)

{

if (timesApply <= 1)

return funct(arg);

else return (apply(funct,

apply(funct, arg, timesApply-1), 1));

}

}

}

wherein the function of adding 5 to an argument is applied 4 times, to the
argument 1, in the method startButton_Click.

However, this does not address optional parameters, which I do not
understand. If the intent is to to default the timesApply to (say 2), you
could define another apply with only 2 parameters, which just invokes the
one with 3 parameters, passing "2" as the third argument. If the intent is
to have the delegate, Funct, have optional arguments, but of differing types
then I don't see that you can do this since C# is strongly typed. You could
define the delegate to take a list of parameters, all of the same type
(possibly Object), I suppose. I don't understand point 3. Perhaps I
addressed points 4 and 5 to some extent. As for point 6, C# does not have a
macro feature, so cannot generate code. Some, but not nearly all, of this
functionality can be duplicated at runtime via generics.

Since all functions in C# must be in some class, it does not map to a purely
functional language. However, the class Foo is arbitrary, and I don't see
that you need to subclass it (but it probably this has something to do with
optional parameters, which I don't understand). Note that Foo itself is not
a generic class. That would give you another level of genericness, but I
don't see what purpose it would serve.

Perhaps this helps; sorry if I have missed some of your points.



"Jon Harrop" <jo*@ffconsultancy.comwrote in message
news:46**********************@ptn-nntp-reader02.plus.net...
>
I am trying to learn C# and .NET programming in general but I am finding
it
very hard going. To start with, I'd like to translate some trivial
functions from other languages that I am familiar with into C#.

Here is a simple function in OCaml that nests "n" applications of "f"
around "x", with "n" defaulting to "n=2":

let rec nest ?(n=2) f x = if n=0 then x else nest ~n:(n-1) f (f x)

For example, "nest f x" gives "f(f(x))" and "nest ~n:3 f x"
gives "f(f(f(x)))".

I am unable to write this elegantly in C#. This is the best I've come up
with and it doesn't even support partial application (currying):

class Program
{
abstract class Nest<T>
{
int n;

public Nest()
{
n = 2;
}

public abstract T f(T x);

public T Apply(T x)
{
while (n 0)
{
x = f(x);
--n;
}

return x;
}

public int N
{
get
{
return n;
}

set
{
n = value;
}
}
}

class NestTwice : Nest<int>
{
public override int f(int x)
{
return 2 * x;
}
}

static void Main(string[] args)
{
NestTwice nestTwice = new NestTwice();
nestTwice.N = 3;
System.Console.WriteLine(nestTwice.Apply(2));
}
}

So I've implemented the higher-order function "nest" as an abstract base
class "Nest" that you must derive from and override the "f" member
function. The optional argument "n" in the OCaml is implemented as a
mutable property "N" with its default value set to 2 by the constructor.

The "NestTwice" class derives from the "Nest" class, specialized to the
type "T=int", and implements the "f" member such that it doubles its
integer argument.

The main program then constructs an object of the class "NestTwice", sets
its property "N" to 3, overriding its default value of 2, and calls
the "Apply" method to compute the equivalent of "nest n f".

Needless to say, there are many aspects of this that I am not happy with!

1. Can the handling of the function argument "f" be written more elegantly
(but still generically) in terms of delegates? I'd like to replace my
C++-style abstract "Nest" class with something like:

public static T nest<T>(int n, Delegate<T, Tf, x) {
while (n>0) { x=f(x); --n; }
return x;
}

2. My handling of optional arguments is hideous. Can this be done without
mutation, i.e. without first setting the option to its default and then
altering it to the specified value?

3. Is there a simpler way of getting the return value of a function with
optional arguments than making up a "standard" member called "Apply" and
giving it the non-optional arguments after the optional ones have settled
to their true values?

4. Can the "Nest" class be derived from a statically-typed delegate class?

5. Did I miss something fundamental in C#: can any of this be written more
succinctly or elegantly in C#?

6. Are there any tools that can help by autogenerating code like this? Are
there any .NET languages that can do this as elegantly as OCaml?

My motivation is largely to write better F# code rather than C# but both
languages have the same implementation of optional arguments, so the F#
equivalent of the OCaml one-liner also entails a page of classes, mutation
etc.

--
Dr Jon D Harrop, Flying Frog Consultancy
The F#.NET Journal
http://www.ffconsultancy.com/product...ournal/?usenet

May 24 '07 #3
Jon Skeet [C# MVP] wrote:
Points to note:
1) Use a generic delegate instead of overriding. Apart from
anything else, this makes life a lot simpler when anonymous methods
are available
Ingenious.
2) There's no real need for a separate class with state
Yes. That was a C++ism.
3) Use overloading to provide optional parameters
I'm concerned that this doesn't scale to having more optional arguments.
4) Use a for loop instead of while to be idiomatic
Right.
5) Boy is it shorter ;)
Wonderful. Thanks for the help!

--
Dr Jon D Harrop, Flying Frog Consultancy
The F#.NET Journal
http://www.ffconsultancy.com/product...ournal/?usenet
May 25 '07 #4
Jon Harrop <jo*@ffconsultancy.comwrote:
3) Use overloading to provide optional parameters

I'm concerned that this doesn't scale to having more optional arguments.
When you've got lots of related parameters, encapsulate them into a
class on their own, with default values.

See
http://www.yoda.arachsys.com/csharp/...ermanager.html
for an example of this.

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet
If replying to the group, please do not mail me too
May 25 '07 #5
On May 25, 9:20 am, Jon Skeet [C# MVP] <s...@pobox.comwrote:
Jon Harrop <j...@ffconsultancy.comwrote:
3) Use overloading to provide optional parameters
I'm concerned that this doesn't scale to having more optional arguments.

When you've got lots of related parameters, encapsulate them into a
class on their own, with default values.

Seehttp://www.yoda.arachsys.com/csharp/miscutil/usage/buffermanager.html
for an example of this.

--
Jon Skeet - <s...@pobox.com>http://www.pobox.com/~skeet Blog:http://www.msmvps.com/jon.skeet
If replying to the group, please do not mail me too
Hi,

Furthermore,
Use the Command Design Pattern to encapsulate lot's of parameters.

Moty

May 25 '07 #6
"Jon Harrop" <jo*@ffconsultancy.comwrote in message
news:46**********************@ptn-nntp-reader02.plus.net...
>
Ingenious.
Yep.
Jon does stuff like this all the time. It's almost scary...

- Michael S
May 25 '07 #7
Moty Michaely wrote:
Use the Command Design Pattern to encapsulate lot's of parameters.
Can you elaborate on this?

I've read this description of the pattern:

http://www.exciton.cs.rice.edu/JAvaR...ns/command.htm

and I can't see how it is relevant. Is this for when you have a set of
optional arguments that are common to several different functions?

--
Dr Jon D Harrop, Flying Frog Consultancy
The F#.NET Journal
http://www.ffconsultancy.com/product...ournal/?usenet
May 26 '07 #8
On May 26, 4:59 am, Jon Harrop <j...@ffconsultancy.comwrote:
Moty Michaely wrote:
Use the Command Design Pattern to encapsulate lot's of parameters.

Can you elaborate on this?

I've read this description of the pattern:

http://www.exciton.cs.rice.edu/JAvaR...ns/command.htm

and I can't see how it is relevant. Is this for when you have a set of
optional arguments that are common to several different functions?

--
Dr Jon D Harrop, Flying Frog Consultancy
The F#.NET Journalhttp://www.ffconsultancy.com/products/fsharp_journal/?usenet
Hi,

When you need to pass common arguments (not necessarily optional) you
can encapsulate the arguments with a class and implement a function in
that class..

For example (very simple one, you can always elevate it to much more
complex one):

To copy a file we can do this:
void CopyFile(string src, string dest)

Or we can encapsulate the CopyFile operation to a FileOperation class:

class FileOperationContext
{
string source;
string destination;

public FileOperationContext(string source, string destination)
{
this.source = source;
this.destination = destination;
}

}

abstract class FileOperation {
FileOperationContext context;

public FileOperation(FileOperationContext context)
{
this.context = context;
}

void Operate();
}

class FileCopy : FileOperation
{
public FileCopy (FileOperationContext context) : base(context)
{ }

override Operate() {
System.IO.File.Copy(context.source, context.destination);
}
}

You can of course not implement methods and just use the class as an
argument list..
for example:

void CopyFile(FileOperationContext context) {
System.IO.File.Copy(context.source, context.destination);
}

void MoveFile(FileOperationContext context) {
System.IO.File.Move(context.source, context.destination);
}

etc....

Hope this clears things up.. =)

Moty

May 26 '07 #9

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

4
by: Mark Stijnman | last post by:
A while ago I posted a question about how to get operator behave differently for reading and writing. I basically wanted to make a vector that can be queried about whether it is modified recently...
385
by: Xah Lee | last post by:
Jargons of Info Tech industry (A Love of Jargons) Xah Lee, 2002 Feb People in the computing field like to spur the use of spurious jargons. The less educated they are, the more they like...
7
by: beza1e1 | last post by:
I'm writing a parser for english language. This is a simple function to identify, what kind of sentence we have. Do you think, this class wrapping is right to represent the result of the function?...
2
by: DBC User | last post by:
Hi Sharpies, I have a C program I am converting it into C#. Everything is fine except this process creates a 6K byte binary file. This file initially filled with 6K null and then start...
6
by: cdecarlo | last post by:
Hello, I've often found that I am writing little scripts at the interpretor to read a text file, perform some conversion, and then write the converted data back out to a file. I normally...
22
by: JoeC | last post by:
I am working on another game project and it is comming along. It is an improvment over a previous version I wrote. I am trying to write better programs and often wonder how to get better at...
9
by: jerry.upstatenyguy | last post by:
I am really stuck on this. I am trying to write a string array containing a "word" and a "definition" to a class called Entry. Ultimately this will end up in another class called dictionary. No,...
10
by: Phillip Taylor | last post by:
Hi guys, I'm looking to develop a simple web service in VB.NET but I'm having some trivial issues. In Visual Studio I create a web services project and change the asmx.vb file to this: Imports...
0
ashitpro
by: ashitpro | last post by:
Writing System Call Wrappers in User Space. Recently I saw a post in Linux/Unix section to know the user who deleted the file in linux. Currently there is nothing in linux which could achieve...
0
by: taylorcarr | last post by:
A Canon printer is a smart device known for being advanced, efficient, and reliable. It is designed for home, office, and hybrid workspace use and can also be used for a variety of purposes. However,...
0
by: aa123db | last post by:
Variable and constants Use var or let for variables and const fror constants. Var foo ='bar'; Let foo ='bar';const baz ='bar'; Functions function $name$ ($parameters$) { } ...
0
by: ryjfgjl | last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.