Functional Swift by objc.io
This repository contains sample code from the Functional Swift book.
Issue repository for the Functional Swift book
Home Page: http://www.objc.io/books/fpinswift
This repository contains sample code from the Functional Swift book.
The text reads:
"Suppose we have the following dictionary, associating capital cities with their inhabitants:
let capitals = ["France": "Paris:, etc]"
However, the dictionary is associating the Countries to their Capitals and not cities to their inhabitants.
So the text should be changed to:
"Suppose we have the following dictionary, associating countries to their capitals:"
Another small query:
The code at the bottom of the same page (PDF 54).
func >>=<U, T> (optional: T?, f: T -> U?) -> U?
I'm not sure here but I think that f: T -> U? should be f: T -> U ( no optional U?) as the function will only be called if the value is not nil.
The func map on page 52 shows that same scenario:
fun map<T, U>(optional: T?, f: T -> U) -> U?
This may be a little pedantic, but by page 66 you have only implemented conformance to the Arbitrary protocol for Int and String, but you use an example that uses CGSize. It might be better to choose an example which builds on Int or String rather than something you have not presented, or mention in the text that an extension to CGSize would have to be written so that it conforms to Arbitrary before the example would work. Otherwise a reader (not looking at anyone in particular) may be puzzled as to how Swift was able to produce an arbitrary CGSize from functions to provide arbitrary Ints and Strings.
On page 86,
func >>> <A, B, C>(f: A -> B, g: B -> C) -> A -> C {
return { x in g(f(x)) }
}
You said that
As there is nothing else we know about C, there is no other possible value that we can return.
Can you explain more, I still find it not clearly enough
After purchasing the book the gumroad popup said I was added to some github repo to access the book content, but it never asked me for my github username, therefore I don't have access to the repo.
How can I get the access to the repo https://github.com/objcio/fpinswift-beta ?
Value Types vs. Reference Types.
I think that there is a mistake in this paragraph:
In this example, the assignment to sameStructPoint.x
does not update the original strutPoint, because structs are reference
types.
Surely, you meant to say that structs and value types.
The following snippet from the CIFilter
extension contains type information that the compiler can infer:
for (key, value: AnyObject) in parameters {
setValue(value, forKey: key)
}
It can be more succinctly written as:
for (key, value) in parameters {
setValue(value, forKey: key)
}
Notice that : AnyObject
has been removed.
I am using iBooks v1.1 on Yosemite to view the ePub version of your book. I noticed that none of the syntax coloring and Figure numbers show up when compared to the PDF version (see below for a comparison). As you can see in the comparison images, the PDF version is much easier to read and the formatting is more consistent.
ePub version:
PDF version:
enum Tree<T> {
case Leaf
case Node(Box<Tree<T>>, T, Box<Tree<T>>)
}
this declaration, which used to work just fine, now compiles but hangs the playground during runtime. I've found the fix in the swiftz library, which is to wrap the middle argument as a closure
enum Tree<T> {
case Leaf
case Node(Box<Tree<T>>, @autoclosure () -> T, Box<Tree<T>>)
}
of course, by doing that, we get a closure of type () -> T
from the middle element. Any code assumes that its T must change as well. Such as
func elements<T>(tree: Tree<T>) -> [T] {
switch tree {
case let Tree.Leaf:
return []
case let Tree.Node(left, x, right):
return elements(left.unbox) + [x()] + elements(right.unbox)
}
}
where we now create the single element array using [x()]
At the bottom there is the following definition:
let pMultiplier = curry { ($0, $1) } </> (op("*") <|> op("/"))
<*> pPrimitive
Which means pMultiplier is either '*' or '|' followed by pPrimitive. However, the text below says that
"The result of the pMultiplier parser is tuples consisting of the operator
string (e.g. "+")"
Wrong. The operator string can be only '*' or '|'
In chapter 10 "We calculate the size and just use NSViews method, dataWithPDFInsideRect, to get the PDF data." should have an apostrophe i.e. "NSView's"
In the definition of function pure for Regions (bottom of the page) there is a typo:
return Region.Region { pos in value }
should be changed to just
return Region { pos in value }
We would need to add the code for drawing a rectangle, but also update the drawing code to move some of the other objects to the right. In Core Graphics, we always describe how to draw things. In this chapter, we’ll build a library for diagrams that allows us to express what we want draw. For example, the first diagram can be expressed like this:
The grammatical mistake is in bold.
At the bottom of p. 128 there is the following:
"For the sake of convenience, we provide two initializers: one that counts
down from an initial number start, and one that is passed an array and
initializes the element to the array’s last valid index."
However, there is only 1 initializer in the corresponding code snippet (the one that takes an array as input). I cannot find any variable named 'start' in class CountdownGenerator.
Definitely a matter of preference, but have you considered that:
typealias Parameters = Dictionary<String, AnyObject>
...can be re-written more succinctly as:
typealias Parameters = [String: AnyObject]
Of course, you may prefer the former to the latter. In which case, please ignore this issue!
Related to #42.
On page 184,
enum Result<T> {
case Success(T)
case Failure(NSError)
}
Unfortunately, generic associated values are not supported by the current Swift compiler. But there is a workaround — defining a dummy wrapper Box:
Is this still necessary? Because you said that Optional is Swift is implemented like this
enum Optional<T> {
case None
case Some(T)
// ...
}
It is a vanity thing, really, but you should be including something like this:
<dc:creator opf:file-as="Eidhof, Chris" opf:role="aut">Chris Eidhof</dc:creator>
<dc:creator opf:file-as="Kugler, Florian" opf:role="aut">Florian Kugler</dc:creator>
<dc:creator opf:file-as="Swiertstra, Wouter" opf:role="aut">Wouter Seierstra</
On page 187 the book describe's creating a swift version of NSSet.
The code you include for set insertion is this:
func setInsert<T>(x: T, set:[T]) -> [T] {
return [x] + set
}
This however is not proper set insertion as it allows for duplicates in the set.
The code should be something like the following in order to prevent insertion of duplicates:
func setInsert<T>(x: T, set:[T]) -> [T] {
return setContains(x, set) ? set : [x] + set
}
It's a small error, but it wouldn't be a set if it had duplicates. It would be a bag.
Just FYI, I came across a couple of typo while I was reading my copy of the PDF version.
Page 78 (3 typos) -
"What are the values of structpoint and sameStructPoint". structpoint
should be written structPoint
to match the variable in the source.
"In this example, the assignment to sameStructPoint.x does not update the original strutPoint," strutPoint
should be spelled structPoint
to match the variable name in the source.
"because structs are reference types." I am pretty sure you mean to say value types. This one is the most important since it is the opposite of the intended meaning.
Page 91 -
In the source code,
println("File succesfully opened..")
succesfully should be spelled successfully.
Thanks for your work on this great book!
In "Case Study: Better Shrinking in QuickCheck", a removeAnElement function is written. But in the next "A More Functional Approach" section it seems to be called removeElement, and sometimes removeAnElement.
When using a night display mode in iBooks (the one with black background and white text) some of the figures (Tries, marked fig 9.1 in pdf, Bar graph, marked fig 10.3 in pdf) are not visible, due to the transparent image background and black contents.
Since the move to this repository I am not able to access the book. Is there anything to do that I did not?
I'm having problems getting the code for Chapter 3 to work, both on my own and in the playground. On line 57 I'm getting crashes. Is this a playground or framework bug? Or am I doing something wrong?
In my own playground the error I get is this:
ImageIO: CGImageSourceCreateWithURL CFURLCreateDataAndPropertiesFromResource failed with error code -14.
I just opened another issue and to illustrate my point I wanted to paste the code from the book I was referring to, but when I do that (using the PDF, with Preview on OS X), I get something like:
The same thing happens with text.
In first example there is a shift method. It says:
The call shift(offset, region) moves the region to the right and up by offet.x and offset.y, respectively.
Here is the implementation from the book:
func shift(offset: Position, region: Region) -> Region {
return { point in
let shiftedPoint = Position(x: point.x + offset.x,
y: point.y + offset.y)
return region(shiftedPoint)
}
}
I think the correct implementation needs to be like this:
func shift(offset: Position, region: Region) -> Region {
return { point in
let shiftedPoint = Position(x: point.x - offset.x,
y: point.y - offset.y)
return region(shiftedPoint)
}
}
Here is the example that needs to return true, shifting circle with radius 100 to right by 70 point, need to contain (100, 100) point
shift(Position(x:70, y:70), circle(100))(Position(x:100, y:100))
The code in Chapter 3 crashes:
typealias Filter = CIImage -> CIImage
typealias Parameters = Dictionary<String, AnyObject>
// This extends CIFilter by adding convenience initializer and a computed property "outputImage"
extension CIFilter {
convenience init(name: String, parameters: Parameters) {
self.init(name: name)
setDefaults()
for(key, value: AnyObject) in parameters {
setValue(value, forKey: key)
}
}
var outputImage: CIImage {
return self.valueForKey(kCIOutputImageKey) as CIImage
}
}
func blur(radius: Double) -> Filter {
return { image in
let parameters: Parameters = [
kCIInputRadiusKey: radius,
kCIInputImageKey: image
]
let filter = CIFilter(name: "CIGaussianBlur", parameters:parameters)
return filter.outputImage
}
}
If I write on my on then it works:
let blurRadius = 8.0
let filter = CIFilter(name: "CIGaussianBlur")
filter.setDefaults()
filter.setValue(blurRadius, forKey: kCIInputRadiusKey)
filter.setValue(ciImage, forKey: kCIInputImageKey)
let blurredImage:CIImage = filter.valueForKey(kCIOutputImageKey) as CIImage
// This crashes:
let blurredImage:CIImage = blur(blurRadius)(ciImage)
Version 2014-10-01, page 10, first paragraph:
By your definition of functions as "first-class values" functions (closures) are also first class values in Apple-C and hence Objective-C and I agree they are.
Since I understand your book to be a praise for Swift in comparison to Objective-C, it would be helpful to elaborate on the differences regarding the use/usability of functions/closures in those languages. If this is not appropriate in an introductory chapter like "thinking Functionally" I would at least expect some pointers/keywords in the above mentioned paragraph with a promise to clarify later in the book.
Are you guys planning on releasing a mobi version as well? I would really appreciate that. PDF's look ugly and unfriendly on kindle and it doesn't support ePub file format.
Thanks,
Faheem
Xcode 6.0.1, on OS X 10.9.5, will not open any of the Playgrounds. It puts up an alert that says "Playgrounds targeting OS X are not supported in this version of Xcode."
I have the eBook and it's showing "117 of 284" anyway, it's the section where we are about to return an enum from the readFile
function.
The enum type is called ReadFileResult
and in the following paragraph you refer to it as OpenFileResult
.
Thanks
The text reads:
In this example, the assignment to sameStructPoint.x does not update the original strutPoint, because structs are reference types.
I believe it should be value types.
I'm getting an error in my iOS Playground when working through Chapter 3 (page 27).
It seems I'm not the only one: https://twitter.com/Gernot/status/507967281717325825, and there may be a Mac OS vs. iOS Playground issue. If this is widespread, and given that the prior code uses NSColor, perhaps it would be worth a note to use the Mac OS-type Playground.
xCode Version 6.0.1 (6A317)
Should this paragraph reference computeIntArray
instead of genericComputeArray
? Quote from the ePub version (it says 64
in the margin):
func computeIntArray(xs: [Int], f: Int -> T) -> [T] {
return map(xs, f)
}Once again, the definition of the function is not that interesting: given two arguments, xs and f, apply map to (xs, f), and return the result. The types are the most interesting thing about this definition. The
genericComputeArray
is an instance of the map function, only it has a more specific type.
P.S. I pasted a bit of context for you to find where it is in the book. Is there an easier way to reference chapters from within iBooks?
I feel really dumb asking this, but could you provide a sample trie for the Chapter 9 discussion, similar to the Trees that were shared "by hand"?
e.g.
let leaf: Tree<Int> = Tree.Leaf
let five: Tree<Int> = Tree.Node(Box(leaf), 5, Box(leaf))
let trie1 = Trie.Make(true, <some recursive dictionary?>)
This is an awesome chapter, but trying to wrap my head around inserting a recursive associative value (?) in an collection of enum cases... is blowing my mind.
help?
The two circles (cyan and green) being drawn in chapter 10 are the same relative size as the first (blue) square. However they are constructed using a radius argument.
Surely that should be diameter?
Chapter 10 gets a bit confused between "ellipsis" and "ellipses".
The former is the three dot character used in menus and elsewhere…
The latter is the plural of ellipse, and is the shape you're drawing :-)
When I open 14-Functors-and-all-that-jazz.playground, there are many error occur especially on the Region section.
Also I don't understand on
func intersection(region1: Region<Bool>, region2: Region<Bool>) -> Region<Bool> {
return pure(&&) <*> region1 <*> region2
}
I think the Region<A->B> in <> can take 1 argument but the && take 2 arguments. As of my understanding, the <> function could be prefix or postfix not infix. Also the compiler also said that 'Bool is not a subtype of (T, @autoclosure () -> U)'
Could you explain this function more clearly?
On page 94,
func ??<T>(optional: T?, defaultValue: T) -> T {
if let x = optional {
return x
} else {
return defaultValue
}
}
You said that
There is one problem with this definition: the defaultValue may be evaluated, regardless of whether or not the optional is nil
Can you elaborate more, what do you mean by "the defaultValue may be evaluated" ?
Sometimes, the syntax highlighting is incorrect or misleading:
\(foo)
part) have the same color as the encompassing string.??
operator, optional
is used to refer to a function parameter, but is highlighted as if it were a reserved keyword in the language, which is rather confusing there. The same thing is true on the subsequent pages where optional
is used as an identifier.For completeness sake, you might add note to the flatten<T>(xss: [[T]]) -> [T]
example implementation (page 42) that the arrays should contain similar types. The example will fail if you mix types in the constituent arrays:
let anArrayOfArrays = [arrayOfInts, arrayOfStrings]
func flatten<T>(xss: [[T]]) -> [T] {
var result : [T] = []
for xs in xss {
result += xs
}
return result
}
flatten(anArrayOfArrays)
But, it will succeed if anArrayOfArrays = [arrayOfInts, arrayOfInts]
. The clarification could appear as:
We can use reduce to define new generic functions. For example, suppose that we have an array of arrays containing similar types that we want to flatten into a single array. We could write a function that uses a for loop:
Interestingly, the subsequent flattenUsingReduce<T>(xss: [[T]]) -> [T]
does not suffer from this issue. I suppose it's a difference in the addition operator.
flattenUsingReduce([arrayOfInts, arrayOfStrings])
func incrementOptional2(optional: Int?) -> Int? {
return optional.map { x in x + 1 }
}
Optional
should start with uppercase if it's a type name
The book says "The call shift(offset, region) moves the region to the right and up by offet.x and offset.y, respectively." if so, shouldn't the shiftedPoint be calculated let shiftedPoint = Position(x: point.x - offset.x, y: point.y - offset.y) (- instead of +).
If I understand it correctly the shift function gives us an 'illusion' of our region being moved by correctling the point position.
If the original regions origin was (0,0) with radius 2, point (5,5) is outside of the region. But if the regions origin was (5,5) with radius 2, point (5,5) would be inside of the region. And the original function version from the book gives a 'false'.
let checkPoint: Position = Position(x: 5.0, y: 5.0)
let regionFunctionOrg = circle(2.0)
regionFunctionOrg(checkPoint) // false -> correct
let regionFunctionAlt = shift(Position(x: 5.0, y: 5.0), regionFunctionOrg)
regionFunctionAlt(checkPoint) // false -> incorrect, should be true.
Thanks
Version 2014-10-01, page 89, first paragraph:
There is no such thing as an "Objective-C function"
On page 55,
There is a third way to curry functions in Swift. Instead of constructing the closure explicitly, as we did in the definition of add2, we can also define a curried version of add1 as follows:
func add3(x: Int)(y: Int) -> Int {
return x + y
}
You said that
transform a function that expects multiple arguments into a series of functions that each expect one argument
so what function does return x+y
belongs to
Also, I think that this is a very interesting feature of Swift, you should elaborate more
Small issue (and this very well may be intentional), but something that stood out to me when reading the section on Reduce:
“Once again, reduce is defined in Swift’s standard library as an extension to arrays. From now on, instead of writing reduce(xs, initialValue, combine), we will use xs.reduce(initialValue, combine).”
But your implementation of reduce is used in the next few examples of flattenUsingReduce, mapUsingReduce, and filterUsingReduce instead of the standard library reduce.
Really enjoying the book so far, thank you!
In the PDF version, 2014-10-01, page 78 has "... because structs are reference types". This should presumably end with "value types".
Note that we have one branch for each of our four different encoding schemes. If we leave any of these branches out, the Swift compiler warns us that the toNSStringEncoding function’s switch statement is not complete. Once again, this static check is not present in the enumerations used in Objective-C.
Clang emits a warning when compiling the following Objective-C code:
typedef NS_ENUM(NSInteger, MyStringEncodingType) {
MyStringEncodingTypeASCII = 1,
MyStringEncodingTypeNotASCII
};
NSString *stringForEncoding(MyStringEncodingType type) {
switch (type) {
case MyStringEncodingTypeASCII:
return @"MyStringEncodingTypeASCII";
}
return @"Not found!";
}
The warning is: Enumeration value 'MyStringEncodingTypeNotASCII' not handled in switch
.
So I think it's fair to say some static checks are available when developing in Objective-C.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.