softshipper
softshipper

Reputation: 34071

Why I need a new primitive?

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

Answers (1)

Alexey Romanov
Alexey Romanov

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 Gens and produce Gens. However, you also need something to apply those combinators to: methods which produce Gens 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 like unit. We were able to define lazyUnit just in terms of other operations. Later, when we pick a representation for Par, lazyUnit won’t need to know anything about this representation—its only knowledge of Par is through the operations fork and unit that are defined on Par.

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

Related Questions