Read "Programming F# A Comprehensive Guide for Writing Simple Code to With this comprehensive book, former F# team member Chris Smith gives you a . ; Imprint: O'Reilly Media; ISBN: ; Language: English. Programming F# and millions of other books are available for Amazon Kindle. Learn more. Enter your ISBN Why is ISBN important?. Editorial Reviews. Book Description. A comprehensive guide for writing simple code to solve Why is ISBN important? ISBN See all 3 versions. Buy. $
|Language:||English, Spanish, Portuguese|
|Genre:||Business & Career|
|ePub File Size:||19.37 MB|
|PDF File Size:||16.52 MB|
|Distribution:||Free* [*Regsitration Required]|
Programming F# , 2nd Edition. 4 reviews. by Chris Smith. Publisher: O'Reilly Media, Inc. Release Date: October ISBN: View table of. An attribution usually includes the title, author, publisher, and ISBN. For example: “Programming F# , Second Edition, by Chris Smith. Copyright Chris. Author: Chris Smith Pages: pages Publisher: O Reilly Media Language: English ISBN ISBN
Cisco Press Download: NET Events 9. This chapter provides a brief introduction to the heart of F —the F compiler, tools, and its place in Visual Studio Get Files takes its parameters as a tuple and therefore cannot be partially applied; all of its parameters must be specified at the same time: Appendixes A.
Are you the publisher? Claim or contact us about this channel. Embed this content in your HTML. Report adult content: More Channels. Channel Catalog Subsection Catalog. Articles on this Page showing articles 1 to 2 of 2. Channel Description: IT eBooks Free Download.
Contact us about this article. NET Discover the power of F 3. Uploaded Link: Alex Ilica. All rights reserved.
Printed in the United States of America. Online editions are also available for most titles http: Rachel Roumeliotis Proofreader: Absolute Service, Inc. Production Editor: Holly Bauer Indexer: Lucie Haskins Copyeditor: Jasmine Kwityn Cover Designer: Karen Montgomery Interior Designer: David Futato Illustrator: Rebecca Demarest October First Edition October Many of the designations used by manufacturers and sellers to distinguish their products are claimed as trademarks. While every precaution has been taken in the preparation of this book, the publisher and authors assume no responsibility for errors or omissions, or for damages resulting from the use of the information contained herein.
Multiparadigm Programming 1. Introduction to F. Functional Programming. Imperative Programming. Object-Oriented Programming. NET Programming. Programming F 7. Applied Functional Programming. Applied Object-Oriented Programming. NET Events 9. Asynchronous and Parallel Programming. For The Array. Data Processing. Extending the F Language Computation Expressions. Generating Derivatives Type Providers. Appendixes A.
Overview of. NET Libraries. F Interop. You might not be willing to fall for such obviously flawed shortcuts, but as your humble author, I will admit that I have. There is elegance to using the right tool for the job. And, just like a hammer or a tape measure, programming languages are tools like any other. This book is about showing you how to use the F programming language as a general purpose tool, with an emphasis on the specific domains where it can lead to dramatic boosts in productivity.
Along the way, you will pick up a knack for functional programming, a semi-mysterious collection of concepts that can help you rethink your programs regardless of the host programming language. Introducing F So what actually is F? In a nutshell, F is a multiparadigm programming language built on. NET, meaning that it supports several different styles of programming natively. In F , you can modify the contents of mem ory, read and write files, send data over the network, and so on.
In F , you can abstract code into classes and objects, enabling you to simplify your code. Being statically typed means that type information is known at compile time, leading to type-safe code. NET language. It runs on the Common Language Infrastructure CLI and so it gets things like garbage collection memory management and powerful class libraries for free.
F also natively supports all. NET concepts e. Even without all the jargon, it is clear that F is a powerful language. However, no pre vious experience with functional programming or. NET is required. If you come from a C or VB. NET background, then you should feel right at home. Although F approaches programming from a different viewpoint, you can apply all of your existing.
NET know-how to programming in F. If you come from an OCaml or Haskell background, then the syntax of F should look very familiar. F has most of the features of those languages, and adds many more to integrate well with. This includes the F compiler and project system, and contains all the features e.
Outside of Visual Studio and on non-Microsoft platforms, you can still write and deploy F applications using the open source Mono platform.
Otherwise, Appendix A will walk you through getting F set up on non- Microsoft platforms. Also, it is important to note that all of the examples printed in this book as well as many more may be found on GitHub. Part I focuses on multiparadigm programming in F. Early chapters are devoted to programming in a specific F paradigm, whereas later ones will help flesh out your understanding of language capabilities.
By the end of Part I you will be fluent in the F language and its idioms. Part II will introduces a few lingering concepts but primarily focuses on applying F in specialized areas. By the end of Part II you will know how to utilize F as a scripting language, for parallel programming, and for creating domain specific languages.
Part III should be considered optional for most F developers, and focuses on advanced language features that allow you to modify and extend the F language. Even if you are familiar with Visual Studio, I recommend you read this chapter, as F has some unique characteristics when it comes to building and running projects.
Chapter 2, Fundamentals Introduces the core types and concepts that will be the foundation for all other chapters. Chapter 3, Functional Programming Introduces functional programming and how to write F code using this style. Chapter 4, Imperative Programming Describes how to mutate values and change program state in an imperative manner. Chapter 5, Object-Oriented Programming Covers object-oriented programming from creating simple types to inheritance and polymorphism.
Chapter 6,. NET Programming Goes over some style independent concepts exposed by the. Part II Chapter 7, Applied Functional Programming Covers more advanced topics in functional programming, such as tail recursion and functional design patterns. Special attention is paid on how to leverage the functional aspects of F to make object-oriented code better. Chapter 9, Asynchronous and Parallel Programming Takes a look at how to use F to take advantage of multiple cores on a processor and the facilities in the F and.
NET libraries for parallel programming. Chapter 10, Scripting Examines F as a scripting language and how to make the most of F script files. Chapter 11, Data Processing Focuses exclusively on using F in real-world scenarios for doing distributed com putations, interacting with web services, and working in information-rich envi ronments.
NET reflection library and how to use it to create declarative programs. Chapter 13, Computation Expressions Introduces an advanced F language feature that will enable you to eliminate re dundant code and add new capabilities to the core F language. Chapter 14, Quotations Introduces F quotation expressions and explains how they can be used to do met aprogramming, as well as to execute F code on other computational platforms. Part IV This book also features a couple of appendixes to flesh out any extra concepts you might be interested in.
Appendix A Does a quick sweep through the existing technologies available on the. NET plat form and describes how to use them from F. Italic Used for new concepts as they are defined. Constant width Used for code examples and F keywords.
Constant width bold Used for emphasis within program code. Pay special attention to note styles within this text. Notes like this are used to add more detail for the curious reader. Warnings are indicated in this style are to help you avoid common mistakes. Using Code Examples This book is here to help you get your job done. In general, you may use the code in this book in your programs and documentation. For example, writing a program that uses several chunks of code from this book does not require permission.
Answering a question by citing this book and quoting example code does not require permission. We appreciate, but do not require, attribution.
An attribution usually includes the title, author, publisher, and ISBN. For example: Copyright Chris Smith, Technology professionals, software developers, web designers, and business and creative professionals use Safari Books Online as their primary resource for research, problem solving, learning, and certification training.
Safari Books Online offers a range of product mixes and pricing programs for organi zations, government agencies, and individuals. For more information about Safari Books Online, please visit us online.
Please let me know of any errors you find, as well as your sugges tions for future editions, at: In addition, you can use analog-mail by writing to: To be put on the mailing list or request a catalog, send email to info oreilly. To comment on the book, send email to bookquestions oreilly. NET DevCenter at http: This chapter provides a brief introduction to the heart of F —the F compiler, tools, and its place in Visual Studio If you are already familiar with Visual Studio, you should still skim through this chapter.
Creating and debugging F projects works just like C or VB. NET; however, F has a unique characteristic when it comes to multiple-file projects. In addition, F has a feature called F Interactive that will dramatically increase your productivity. Not to be missed! Open up Notepad or your favorite text editor and create a new file named HelloWorld.
To compile this application, use the F compiler, fsc. The following snippet shows calling the F compiler on the command line to build and run your application: All Rights Reserved. Visual Studio 11 Tools are the lifeblood of any programming language, and F is no different.
Like C and VB. NET, F is a first-class citizen in Visual Studio, with all the features that you might expect, including debugger support, IntelliSense, project templates, and so on. Alternatively, you can try F out in your browser. Figure Select F Application to start your first F project 4 Chapter 1: Next, type the following code into the F editor: When your application starts, a console window will appear and display the entirely unsurprising result shown in Figure The code in Example will create a program that accepts two command-line parameters and prints them to the console.
In addition, it displays the current time. Example ToString "hh: Values Example introduces three values named greeting, thing, and timeOfDay: It is worth pointing out that unlike most other programming languages, values in F are immutable by de fault, meaning they cannot be changed once initialized.
However, the name must begin with a letter or an underscore. This allows you to refer to values and functions exposed from other. NET languages that may conflict with F keywords: However, programmers typically indent their code to make it more readable anyway, so these extra symbols often just add syntactic clutter.
The F compiler allows you to use whitespace to delimit code blocks. For example, anything indented more than the if keyword is considered to be in the body of the if statement.
Because tab characters can indicate an unknown number of space characters, they are prohibited in F code. Reviewing Example , notice that the body of the main method was indented by four spaces, and the body of the if statement was indented by another four spaces: Possible incorrect indentation: Try indenting this token further or using standard formatting conventions.
The general rule is that anything belonging to a method or statement must be indented farther than the keyword that began the method or statement. So in Example , ev erything in the main method was indented past the first let and everything in the if statement was indented past the if keyword.
As you see and write more F code, you will quickly find that omitting semicolons and curly braces makes the code easier to write and much easier to read. Visual Studio 11 7. NET libraries: Now property from the System namespace in the mscorlib.
NET Framework contains a broad array of libraries for everything from graphics to databases to web services. F can take advantage of any. NET library natively by calling directly into it. Conversely, any code written in F can be consumed by oth er. NET languages. This also means that F applications can run on any platform that supports.
So the F programs you write can run on phones, tablets, PCs, and so on. For more information on. For more information about F interoperating with other. NET languages, refer to Appendix B. Comments F allows you to comment your code. Everything between the two tokens will be ignored: XML documentation comments F Interactive So far you have written some F code and executed it, and the rest of the book will have many more examples. The FSI window will not only make it much easier to work through the examples in this book, but it will also help you write applications.
It accepts F code, compiles and executes it, then prints the results. This allows you to quickly and easily experiment with F without needing to create new projects or build a full application to test the results of a code snippet. Once the FSI window is available, it accepts F code until you terminate the input with ;; and a newline. The code entered is compiled and executed as shown in Figure The FSI window prints any new values introduced as well as their types.
Figure shows val x: If the FSI window evaluates an expression that was not assigned to a value, it will instead assign it to the name it. For example, in Figure the value x was introduced with type int and value If you are running F without Visual Studio, you can find the console version of F Interactive in the same directory you found fsc. Try running these other snippets in FSI. Remember that every code snippet is terminated with a ;;: After selecting all the code in Example within the code editor and pressing Alt- Enter, you will see the following in the FSI window: You can find a copy of the source code for all examples in the book on GitHub.
Managing F Source Files When you are starting out with F programming, most of the programs you write will live only in FSI or perhaps in a single code file. Your F projects, however, will quickly grow and be broken up across multiple files and eventually multiple projects.
The F language has some unique characteristics when it comes to managing projects with multiple source files. In F , the order in which code files are compiled is significant. You can only call into functions and classes defined earlier in the code file or in a separate code file compiled before the file where the function or class is used.
If you rearrange the order of the source files, your program may no longer build! The reason for this significance in compilation order is type inference, a topic covered in Chapter 2. The keyboard shortcut for reordering project files is Alt-Up and Alt-Down. Although not exposed by the Visual Studio UI, you can edit the project file directly to achieve this. Many of the in-depth examples of this book utilize this technique 12 Chapter 1: Good luck and have fun! I broke it down to give you a feel for what you were doing, but much of the code is still a mystery.
In this chapter, I provide the necessary foundation for you to understand that code fully, but more importantly, I present several more examples that you can use to grasp the basics of F before you move on to the more complex features. The first section of this chapter covers primitive types, like int and string, which are the building blocks for all F programs.
I then cover functions so you can manipulate data. The fourth section details foundational types such as list, option, and unit. Mastering these types enables you to expand into the object-oriented and functional styles of F code covered in later chapters. By the end of this chapter, you will be able to write simple F programs for processing data. Primitive Types A type is a concept or abstraction, and is primarily about enforcing safety.
Types repre sent a proof of sorts if a conversion will work. Some types are straightforward repre senting an integer , whereas others are far more abstract like a function. F is statically typed, meaning that type checking is done at compile time. For example, if a function accepts an integer as a parameter, you will get a compiler error if you try to pass in a string. NET, F supports the full cast and crew of primitive. NET types, which are standard across most programming languages.
They are built into the F language and separate from user-defined types that you define yourself. For example, the following code defines a new value x in an FSI session. Integer types vary by size, so that some types take up less memory and can represent a smaller range of numbers. Integers can also be signed or unsigned based on whether or not they can represent negative values.
Floating-point types vary in size too; in exchange for taking up more memory, they provide more precision for the values they hold. To define new numeric values, use a let binding followed by an integer or floating-point literal with an optional suffix. The suffix determines the type of integer or floating-point number a full list of available primitive numeric types and their suffixes is provided in Table Numerical primitives in F Type Suffix.
Byte 0 to sbyte y System. UInt16 0 to 65, int, int32 System. Represents values with approximately 15 significant digits.
Represents values with approximately 7 significant digits. Decimal A fixed-precision floating-point type with precisely 28 digits of precision. F will also allow you to specify values in hexadecimal base 16 , octal base 8 , or binary base 2 using a prefix 0x, 0o, or 0b: F will convert the binary value to the floating- point number it represents. When using a different base to represent floating-point numbers, use the LF suffix for float types and lf for float32 types: Table lists all supported operators.
Like most programming languages, integer division rounds down, discarding the remainder. Table To raise the power of an integer value, you must either convert it to a floating-point number first or use the pown function.
By default, arithmetic operators do not check for overflow, so if you exceed the range allowed by an integer value by addition, it will overflow to be negative similarly, sub traction will result in a positive number if the number is too small to be stored in the integer type: F features all the standard mathematical functions you would expect, with a full listing in Table This means that the compiler will not automatically convert primitive data types for you behind the scenes, such as converting an int16 to an int This eliminates subtle bugs by removing surprise conversions.
Instead, to convert primitive values, you must use an explicit con version function listed in Table All of the standard conversion functions accept all other primitive types—including strings and chars.
Convert family of methods, meaning that they throw System. FormatException exceptions for invalid inputs. BigInteger If you are dealing with data larger than , F has the bigint type for representing arbitrarily large integers. Big Integer type. Example defines data storage sizes as bigints.
Bitwise Operations Primitive integer types support bitwise operators for manipulating values at a binary level. Bitwise operators are typically used when reading and writing binary data from files. See Table To define a character value, you can put any Unicode character in single quotes. Characters can also be specified using a Unicode hexadecimal character code. The following snippet defines a list of vowel characters and prints the result of defining a character using a hexadecimal value: An escape sequence is a backslash followed by a special character.
Alternatively, you can get the byte representation of a character literal by adding a B suffix: To access a character from within a string, use the indexer syn tax,. If the last character on a line in a string literal is a backslash, the string will continue on the next line after removing all leading whitespace characters: You can define a ver batim string using the symbol, which takes the verbatim text between the quotation marks and does not encode any escape sequence characters: String";; val normalString: String";; val verbatimString: Boolean as well as standard Boolean operators listed in Table It defines a function called printTruthTable that takes a function named f as a parameter.
That function is called for each cell in the truth table and its result is printed. Comparison and Equality You can compare numeric values using standard greater than, less than, and equality operators listed in Table NET is a complex topic. There is value equality and refer ential equality. For reference types, however, equality is deter mined by overriding the System. Object method Equals. The following defines a function called square that takes an integer, x, and returns its square: So when you define a function, the last expression to be evaluated in the function is what the function returns.
The only thing you need to know for now is that in order to call a function, simply provide its parameters sepa rated by spaces: This expression was expected to have type int but here has type float. Why does the compiler think that this function only takes integers? The reason is due to type inference. The compiler infers their types based on usage.
Be careful not to confuse type inference with dynamic typing. The following FSI session declares a function that will multiply two values. To add a type annotation, simply replace a function parameter with the fol lowing form: To constrain the first parameter of our add function to be a float, simply redefine the function as: Type inference dramatically reduces code clutter by having the compiler figure out what types to use. However, the occasional type annotation is required and can sometimes improve code readability.
Generic Functions You can write functions that work for any type of a parameter—for example, an identity function that simply returns its input: If a parameter is generic, it means that the parameter can be of any type, such as an integer, string, or float.
Just note that whenever you see 'a, it can be an int, float, string, a user-defined type, and so on. Scope Each value declared in F has a specific scope, which is the range of locations where the value can be used. More formally, this is called a declaration space. By default, values have module scope, meaning that they can be used anywhere after their declaration. However, values defined within a function are scoped only to that function. The value or constructor 'functionValue' is not defined.
The scoping of values may not seem like that important of a detail, but one reason you should be aware of it is because F allows nested functions. You can declare new function values within the body of a function. Nested functions have access to any value declared in a higher scope, such as the parent function or module, as well as any new values declared within the nested function.
The following code shows nested functions in action. It helps prevent pollution of the surrounding module by allowing you to keep small, specific functions local to just where they are needed. This will become more apparent once we start programming in the functional style in Chapter 3.
What if you want to declare a value named x, but that value is already used in a higher scope? When this happens, both values exist in memory, except there is no way to access the previously declared value.
This may look like the value of x is changing, but actually it is just creating a new value of x and giving it the same name. The following shows an example of how the code gets compiled: If you want to actually update the value of x, you need to resort to mutability, which is covered in Chapter 4. Control Flow Within a function, you can branch control flow using the if keyword. The condition expression must be of type bool and if it evaluates to true, then the given code is exe cuted, which in the following snippet prints a message to the console: However, something that makes F much different from other languages is that if expressions return a value.
For example, in the following example, the value result is bound to the result of the if expression. With it, you can chain together multiple if expressions without the need for nesting: This expression was expected to have type int but here has type string.
In that case, the clause must return unit, which is a special type in F that means essentially no value. Alter natively, you can think of unit as a manifestation of void from other programming languages. We cover unit in more detail shortly. Core Types Previously we covered the primitive types available on the. NET platform, but those alone are insufficient for creating meaningful F programs.
The F library includes several core types that will allow you to organize, manipulate, and process data. Table lists a set of foundational types you will use throughout your F applications. In fact, these foundational types enable programming in the functional style, as we will see in Chapter 3. It is typically used when calling a function for its side effect and you want to ignore its return value: For example, tuples can be used to track the intermediate results of a computation.
F tuples use the underlying System. To create an instance of a tuple, separate a group of values with commas, and optionally place them within parentheses.
In fact, you can even have a tuple that contains other tuples! The following code snippet defines two tuples. The first, named zeros, defines a tuple of various manifestations of zero. The second, nested, defines a nested tuple.
The tuple has three elements, the second and third of which are themselves tuples: To extract values from two-element tuples, you can use the fst and snd functions. The following example creates a tuple value named snacks. Type mismatch. The tuples have differing lengths of 2 and 3. It is possible to pass tuples as parameters to functions, like any value. Likewise, a function can return a tuple. In the following example, the function tupledAdd takes two param eters, x and y, in tupled form.
Notice the difference in type signature between the add and the tupledAdd functions: Lists Whereas tuples group values into a single entity, lists allow you to link data together to form a chain.
Doing so allows you to process list elements in bulk using aggregate oper ators, discussed shortly. The simplest way to define a list is as a semicolon-delimited collection of values enclosed in brackets, although later you will learn to declare lists using the more powerful list comprehension syntax.
The empty list, which contains no items, is represented by : With more information based on usage, the type inference system would be able to pin it down to a more specific type.
Unlike list types in other languages, F lists are quite restrictive in how you access and manipulate them. In fact, for a list, there are only two operations you can perform.
To see how this limitation can be used to your advantage, refer to Chapter 7. The first primitive list operation is cons, represented by the cons operator, This joins an element to the front or head of a list. The following example attaches the value 'y' to the head of the vowels list: Append joins two lists together.
The following example joins the list odds and the list evens together, resulting in a new list: To declare a list of ordered numeric values, you can use the list range syntax. The first expression specifies the lower bound of the range and the second specifies the upper bound.
The result then is a list of values from the lower bound to the upper bound, each incremented by one: Note that the stepping value can be negative: At the simplest level, a list com prehension is some code surrounded by rectangular brackets, [ ]. The following code snippet shows a list comprehension that defines a function negate and returns the numbers 1 through 10, negating the even ones: The following two code snippets are identical: Example shows how you can use list comprehensions to generate all prime numbers smaller than a given integer.
The example works by looping through all numbers between 1 and the given max value. Then it uses a list comprehension to generate all the factors of that number. It checks if the generated list of factors has only two elements, then it yields the value because it is prime. There certainly are more efficient ways to compute primes, but this demonstrates just how expressive list comprehensions can be.
The built-in methods listed in Table are the primary ways you will interact with lists in F. Common List module functions Function and type Description List. Otherwise returns None. Some and None are covered shortly. The following example demonstrates the List.
The tricky part to note is that List. All of these functions are defined in the List module in the Microsoft. Collections namespace. Because the Microsoft. Collections module is imported by default, to access any of these methods you just need to specify the List module and the function name. The true power of lists lies in aggregate operators, which are a set of powerful functions that are useful for any collection of values.
Each element in the new list is the result of applying the function to an element of the original list. It has type: Visualizing List. Using List. It provides an elegant way for you to transform although used repeat edly, can simplify the structure of code you write. When you have a list of values and you want to distill it down to a single piece of data, you use a fold. There are two main types of folds you can use on lists. Once every list item has been processed, the final accumulator value is returned.
Example demonstrates how to use List. The function insertCommas takes the accumulator and a value and simply returns a new string that joins the accumulator and the value separated by a comma.
When passed to List. Comma separating a list of strings using List. But what if you want something more powerful e. The fold function takes three parameters. First, a function that when provided an accumulator and list element returns a new accumulator. Second, an initial accumulator value. The final parameter is the list to fold over.
The return value of the fold is the final state of the accumulator. Officially the type is: Example folds the characters of a string into a tuple counting the occurrences of each vowel the number of As, Es, Is, etc. The folding function is applied to each letter in the list.
If the letter is a vowel, we return an updated accumulator value; otherwise we just return the existing accumulator. Counting vowels using List. There are alternative functions List. Depending on what you are trying to do, processing a list in reverse order can have a substantial impact on performance. For a more in-depth look at the performance implications of list processing, refer to Chapter 7. The term side effect simply means that executing the function has some side effect other than its return value; for example, printfn has the side effect of printing to the console in addition to returning unit.
Example uses List. The option type has only two possible values: Some 'a and None. Consider the problem of parsing a string as an int.
If the string is properly formatted, the function should return the integer value, but what if the string is improperly for matted? This is a prime situation where you would use an option type. However, null is also used to indicate an uninitialized value. This duality can lead to confusion and bugs. If you use the option type, there is no question what the value represents.
Nullable type, cov ered in Chapter 4. Example defines a function isInteger that tries to parse an integer using the Int TryParse function. If the parsing is successful, the function will return Some re sult ; otherwise it will return None. This enables consumers of the function to know that for some inputs the result may not be defined, hence returning None. TryParse str if successful then Some result else None;; val isInteger: If Option.
Common Option module methods Function and type Description Option. NET System. Console class can be used for writing text to the screen, but printf is better suited for the functional style because its arguments are strongly typed and therefore contribute to type infer ence. Read should still be used for input, however. By providing a format specifier, listed in Table , you can drop in data as well: The type 'float' is not compatible with any of the types byte,int16,int32,int64,sbyte,uint16,uint32,uint64,nativeint,unativeint, arising from the use of a printf-style format string.
To String virtual method. To String. But in reality, every code snippet you have seen so far has been a full program although, admittedly, not the type of programs you imagined. You will see a more real-world view of F in Chapter For now, we need to focus on the organizational building blocks of any F application: Modules All the code we have written so far has been in a module.
By default, F puts all your code into an anonymous module with the same name as the code file with the first letter capitalized. So, if you have a value named value1, and your code is in file1. After that point, every value, function, or type defined will belong to that module: Namespaces are a unit of organizing code just like modules except that namespaces cannot contain values, only type declarations. Also, namespaces cannot be nested in the same way as modules. Instead, you can simply add multiple namespaces to the same file.
Example defines several types inside of two namespaces. Modules are optimized for rapid prototyping and quickly exploring a solution, like you have seen so far. Name spaces, on the other hand, are geared toward larger-scale projects using an object- oriented approach. The subtle difference in when to use a module over a namespace will become clearer as you see more F source code. Program Startup Namespaces and modules are ways to organize the code found within F source files.
But where does the execution of code actually start? In F , the program starts executing at the top of the last code file, which needs to be a module. Consider this simple F program consisting of a single code file: When you press F5 to run your program, nothing will happen. This feature is convenient for rapid prototyping and saves you a few keystrokes, but in larger projects it is better to explicitly define the entry point.
To qualify, your main method must satisfy the following requirements: This ensures there is no confusion on where the F program starts. Arrays are covered in Chapter 4. In the next chapter, you will learn to program using the functional style, enabling you to write more powerful F applications and advance on your journey toward becoming a level 9 F ninja master. In a nutshell, functional programming is about being more declarative in your code. In imperative programming which we cover in Chapter 4 , you spend your time listing out the specific steps to perform a task.
In functional programming, you specify what is to be done, but not how. Even though functional programming is no silver bullet, the result is that programs are much clearer, and some problems—like concurrency and parallel programming—are made much easier.
By the end, you will be able to write purely functional code, and leverage the elegance and simplicity of declarative programming.
A deeper look at functional con cepts, such as tail recursion and closures, comes later in Chapter 7. Consider two functions f and g: For example, in the previous snippets, there was no explicit return type specified. Does f x take an integer or a float? The equiv alent F code is: Functional programming in essence is thinking about computations in an abstract way—again, what is to be computed but not how it gets computed. You can even think of entire programs as functions with their inputs being mouse and keyboard states and the output being the process exit code.
When you begin to view programming in this way, some of the complexity associated with normal programming models goes away. Functions simply take their input and produce an output. Second, algorithms are ex pressed in terms of functions and not classes or objects, so it is easier to translate these concepts using functional programming.
You will see examples of how functional programming can simplify complex code throughout the chapter, but first you need to start thinking in terms of functions. To do so, you need to abandon some of the mind-set built up from existing imperative lan guages. In the next sections, we introduce the notion of immutability, functions as values, and function composition to demonstrate how to begin to program in the functional style.
The reason for this is that the names of things you declare are immutable by default in functional programming, meaning they cannot be changed. If a function somehow changes the state of the program—such as writing to a file or mutating a global variable in memory—that is known as a side effect.
For example, calling the printfn function returns unit, but has the side effect of printing text to the screen. Similarly, if a function updates the value of something in memory, that too is a side effect—something extra the function does in addition to returning a value. If you are used to an imperative programming language, then not being able to have variables may seem like a burden. But immutability offers some significant benefits.
Consider the two functions in Example Both functions simply sum the squares of a list of numbers with one using the imperative style of mutating data and the other using the functional style. The imperative style makes use of a mutable variable, meaning that the value of total changes during the execution of imperativeSum. It starts with the list of numbers, squares each one, and then sums them all up.
Although the F syntax may be unfamiliar, the code is more declarative and maps directly to what you want to have happen. The imperative version, although easier to walk through in your head, requires you to read through the code to understand what is going on.
Please resist this urge, at least for now, because there are some subtle advantages to learning to approach problems in the functional style.
For example, if you wanted to run the imperative version in parallel, then you would have to rewrite the code entirely.
Because you were so detailed in how you specified the program to be run, you would need to restate how the program should work in parallel.
You will see just how easy F makes parallel programming in Chapter Functional programming languages are referred to as pure if they do not allow side effects. F in this regard is considered impure, as it will allow you to change the values of variables when programming in the imperative style.
Function Values In most other programming languages, functions and data are regarded as two very different things. However, in a functional programming language, functions are treated just like any other piece of data. For example, functions can be passed as parameters to other functions.
In addition, functions can create and return new functions!
Functions that take or return other functions as their inputs or outputs are known as higher-order functions, and are key for idiomatic functional programming. This capability enables you to abstract and reuse algorithms in your code. You saw an example of this in Chapter 2 with List.
Example defines a function, negate, which negates a single integer. When that function is passed as a parameter to List. For example, our negate function in Example will probably never be used anywhere else in the program except when negating a list. The following snippet creates a lambda expression and passes the value 5 as a parameter.
When the function is executed, the parameter x is incremented by 3 and the result is 8: As they grow larger, they become more difficult to debug. This is especially true if you find yourself copy ing and pasting lambdas around in your code. Partial function application Another example of higher-order functions in practice is partial function application. Partial function application is the ability to specify some subset of the parameters of a function, and produce a new function where those parameters are fixed.
For example, f x, y, z can be partially applied with x and y to just be f' z. IO let appendFile fileName: WriteLine text file. Close ;; val appendFile: You would have to keep around the path to your log file and always pass it in as the first parameter. It would be nice, however, to create a new version of appendFile where the first parameter is fixed to our verbatim string "D: You can achieve this by partially applying the first parameter of appendFile, which produces a new function that only takes one parameter, the message to be logged: The appendFile function had type: To understand what is going on behind the scenes, let me introduce currying.
The ability to transform a function taking n arguments into a chain of n functions, each taking one argument, is called currying. Both are function types that take two string parameters and return an integer. This means that all parameters must be specified at the same time. Currying and partial function application may not look particularly powerful, but it can dramatically improve the elegance of your code.
Consider the printf function that takes a format string as a parameter followed by the values to fill in that format string. The following example shows how you can pass a partially applied version of printf to avoid the need for a lambda expression: Although partially applied functions can make code simpler, they can also make code harder to debug.
Be careful not to abuse currying; otherwise you run the risk of making your programs more complex than they need to be. Functions returning functions With functional programming treating functions like data, it is possible for functions to return other functions as values.