Reputation: 34071
I am learning functional programming in Scala and reading the book FPiS.
One the page 131 about API design(algebra), the author mentioned following:
As we discussed in chapter 7, we’re interested in understanding what operations are primitive and what operations are derived, and in finding a small yet expressive set of primitives. A good way to explore what is expressible with a given set of primitives is to pick some concrete examples you’d like to express, and see if you can assemble the functionality you want. As you do so, look for patterns, try factoring out these patterns into combinators, and refine your set of primitives. We encourage you to stop reading here and simply play with the primitives and combinators we’ve written so far. If you want some concrete examples to inspire you, here are some ideas:
What does he mean with expressive primitives? What is a primitive?
(The chapter 7 does not explain about primitive at all.)
I am imaging, a primitive is a smallest thing of something that can be build with combinator to get a higher level thing.
The question from the book:
If we can generate a single
Int
in some range, do we need a new primitive to generate an(Int,Int)
pair in some range?
What is the answer of the question?
Is Int
a primitive?
What is a primitive function?
Upvotes: 0
Views: 166
Reputation: 170733
What is a primitive?
I am imaging, a primitive is a smallest thing of something that can be build with combinator to get a higher level thing.
Right. So in this case: you are developing an API which has type Gen[A]
denoting "a generator of values of type A
". Combinators in this API will be methods which operate on Gen
s and produce Gen
s. However, you also need something to apply those combinators to: methods which produce Gen
s without starting with one.
One of these may be range(min: Int, max: Int): Gen[Int]
. If you now need a pairInRange(min: Int, max: Int): Gen[(Int, Int)]
, do you need to implement it in the same way range
is implemented, or can you build it from range
using combinators? And if you can, what combinators do you need? In this case, you should conclude that
def pairInRange(min: Int, max: Int) = pair(range(min, max), range(min, max))
is a reasonable implementation, assuming there is a pair
combinator (think what its type should be), so pairInRange
doesn't need to be a primitive: it's a derived operation. Primitive operations are those which aren't derived.
You could equally have pairInRange
as primitive and def pair(min: Int, max: Int) = pairInRange(min, max).map(_._1)
as derived; this is just an unnatural way to design it!
(The chapter 7 does not explain about primitive at all.)
Now that I've got home and have access to the book: yes, it does. If you search for "primitive" in the book (assuming you have the electronic version), you'll find this quote in 7.1.3 Explicit forking:
The function
lazyUnit
is a simple example of a derived combinator, as opposed to a primitive combinator likeunit
. We were able to definelazyUnit
just in terms of other operations. Later, when we pick a representation forPar
,lazyUnit
won’t need to know anything about this representation—its only knowledge ofPar
is through the operationsfork
andunit
that are defined onPar
.
Note in particular the last sentence, which makes a point I didn't emphasize above. You should also read what follows: there are more explanations in 7.3.
What does he mean with expressive primitives?
A primitive is not expressive, it's a set of primitives (including combinators) that is expressive. That is, it should allow you to express not just range
and pairInRange
but all other generators you want.
Is
Int
a primitive?
No. This is a meaning of "primitive" unrelated to "primitive types" (Int
, Double
, etc.)
Upvotes: 3