Learning F# - Passing Parameters to Functions
December 17, 2015One of the first issues I faced when learning F# was finding out how to specify multiple parameters to a function. While this might sound obvious when learning a functional programming language, I had a few confronting moments that forced me to unlearn things before I could make any progress.
I wanted to create a function that wrapped the Contains method of the String class. In C#, it would be implemented like this:
public class StringHelper
{
public static Boolean Contains(String substr, String str)
{
return str.Contains(substr);
}
}
Calling this simple function is quite obvious:
StringHelper.Contains("pdf", "document.pdf")
My first attempt at writing the equivalent function in F# looked like this:
let contains (substr, str: string) =
str.Contains substr
I had to make a type annotation for the second argument because otherwise the F# compiler was unable to infer its type as a string. Calling this function looks like this:
contains ("pdf", "document.pdf")
All very nice. The code works and life is good. But as it turns out, there’s something going on with this implementation that I didn’t realise at the time. Turns out that the contains function isn’t a function that accepts two string arguments, but a single tuple argument of two strings!
Executing this code in the F# REPL shows the following type annotation for the contains function:
val contains : substr:string * str:string -> bool
I noticed a lot of examples where F# functions were being called without the braces and without commas separating the parameters. Calling the current implementation of the contains function this way gave me the following error:
contains "pdf" "document.pdf"
error FS0003: This value is not a function and cannot be applied
So instead, I removed the braces and comma from the function definition like so:
let contains substr str: string =
str.Contains substr
The compiler then gave me the following error message:
error FS0072: Lookup on object of indeterminate type based on information prior to this program point. A type annotation may be needed prior to this program point to constrain the type of the object. This may allow the lookup to be resolved.
I had quite some head scratching going on before I was finally able to figure this out. Apparently the second argument needs to be enclosed with braces because of the explicit type annotation.
let contains substr (str: string) =
str.Contains substr
contains "pdf" "document.pdf"
This time the F# REPL shows the following type annotation for the contains function:
val contains : substr:string -> t:string -> bool
This wasn’t quite what I expected at the time. As a developer who mostly writes C#, JavaScript code, I noticed how using comma-separated parameter/argument lists within braces was so engrained in my ability to read and write code. Even when dabbling with Clojure in my spare time I got no shortage of braces either. Even when writing Ruby code, I held on to the habit of using comma-separated parameter/argument lists enclosed in braces. I told myself that this would improve the readability of my code. But in fact it was my brain trying to keep me in the comfort zone.
At this point I’m quite comfortable with this syntax in F#. But it definitely took some time getting used to not adding braces/commas all over the place. I must say that the Troubleshooting F# page on Scott Wlaschin’s website was a great help!
Until next time.
If you and your team want to learn more about how to write maintainable unit tests and get the most out of TDD practices, make sure to have look at our trainings and workshops or check out the books section. Feel free to reach out at info. @ principal-it .be
Jan Van Ryswyck
Thank you for visiting my blog. I’m a professional software developer since Y2K. A blogger since Y2K+5. Provider of training and coaching in XP practices. Curator of the Awesome Talks list. Past organizer of the European Virtual ALT.NET meetings. Thinking and learning about all kinds of technologies since forever.
Comments
Writing Maintainable
Unit Tests
Watch The Videos
Latest articles
-
Contract Tests - Parameterised Test Cases
June 28, 2023
-
Contract Tests - Abstract Test Cases
April 12, 2023
-
Contract Tests
February 1, 2023
-
The Testing Quadrant
June 15, 2022
-
Tales Of TDD: The Big Refactoring
February 2, 2022
Tags
- .NET
- ALT.NET
- ASP.NET
- Agile
- Announcement
- Architecture
- Behavior-Driven Development
- C++
- CQRS
- Clojure
- CoffeeScript
- Community
- Concurrent Programming
- Conferences
- Continuous Integration
- Core Skills
- CouchDB
- Database
- Design Patterns
- Domain-Driven Design
- Event Sourcing
- F#
- Fluent Interfaces
- Functional Programming
- Hacking
- Humor
- Java
- JavaScript
- Linux
- Microsoft
- NHibernate
- NoSQL
- Node.js
- Object-Relational Mapping
- Open Source
- Reading
- Ruby
- Software Design
- SourceControl
- Test-Driven Development
- Testing
- Tools
- Visual Studio
- Web
- Windows
Disclaimer
The opinions expressed on this blog are my own personal opinions. These do NOT represent anyone else’s view on the world in any way whatsoever.
About
Thank you for visiting my website. I’m a professional software developer since Y2K. A blogger since Y2K+5. Author of Writing Maintainable Unit Tests. Provider of training and coaching in XP practices. Curator of the Awesome Talks list. Thinking and learning about all kinds of technologies since forever.
Latest articles
Contract Tests - Parameterised Test Cases
Contract Tests - Abstract Test Cases
Contract Tests
The Testing Quadrant
Contact information
(+32) 496 38 00 82
info @ principal-it .be