Upload
others
View
4
Download
0
Embed Size (px)
Citation preview
Collaboration and ManagementDana Fisman
1
Principles of Programming Languages
www.cs.bgu.ac.il/~ppl172
Lesson 5 - Data Types and
Operations on Data
2
Types - what we already know
Types define sets of values There are atomic and compound types
The programmer can define data types and annotate its code in order to reflect the intended meaning of variables and functions
A process called type checking can analyze the program to verify there are no type discrepancies
3
Types - third important role
Type definitions help the programmer structure the code that operates on complex data values in a way that reflects the structure of the data type.
Knowing the structure of a data type helps the programmer write correct functions that operate over values of this type.
And vice versa, the decision on how to design the data type is driven by the operations that need to be preformed on them, and the desire to make them uniform.
4
Types - third important role
We will illustrate this point through four examples:
Homogeneous array types and the sequence interface (map, filter, reduce, …) Disjoint types and Disjoint Unions to enable uniform functional interfaces Modeling trees Mutable data types in FP
5
Homogeneous Array Types and the Sequence Interface
Array values can be ohomogeneous (all items are of the same types) or oheterogeneous (not all items are of the same type)
The natural way to process homogenous arrays is using the sequence interface (the set of higher order functions which can be applied to them) o map o filter o reduce o and others (every, some, find, etc.)
6
Homogeneous Array Types and the Sequence Interface
7
Homogeneous Array Types and the Sequence Interface
Can we always apply map(f,array) on array?
When can we?
When o the array is of type <SomeType>[] and o f is of type <SomeType> => <PossiblyAnotherType>
8
Homogeneous Array Types and the Sequence Interface
When can we apply filter (p?,array) on array?
When o the array is of type <SomeType>[] and o p? is of type <SomeType> => boolean
When can we apply reduce (f, init, array) on array?
When o the array is of type <SomeType>[] and o f is of type <PossiblyOtherType>,<SomeType> => <PossiblyOtherType> o init is of type <PossiblyOtherType>
Heterogenous
arrays do not lend
themselves to map
etc.
9
Creating new data types We have seen various ways to create new data types:
Array types Map types Generic types
We have discussed the set relations among created data types. Can we create new data types simply using set relations?
Cartesian product? Union? Intersection?
10
Typescript Union and Intersection
We can we create new data types simply using typescript’s union and intersection
type NoS = number | string; type SoB = string | boolean; type S = NoS & SoB;
11
Structural vs. Nominal Subtyping
Under nominal typing (as in Java)
these two types are disjoint.
Compiles ok !
Under structural typing (as in Javascript)
these two types are equivalent.
But sometimes
we do want to distinguish
these!
12
Disjoint Types
Does not compile as
desired
Compilation error: Type 'Person' is not assignable to type ‘Variable'.
Types of property 'tag' are incompatible.
The addition of field tag caused the two types to be disjoint!
13
Disjoint Union
By combining type union operator | and a mutual field (tag) with distinct values we can obtain disjoint types.
Mathematical definition:
14
Disjoint Union
15
Disjoint Union
disjoint union together with the corresponding switch
construct achieves an effect similar to sub-classes with
virtual classes in OOP
It allows the function to dispatch to different
computations based on the type of the actual value received as a parameter.
16
Modeling Trees with Types
bt = {“root”:2, "left":{"root":3,"left":{"root":4}}, "right":{"root":5,"right":{"root":6}}}
traverseDFS(bt);
==>2 3 4 5 6
The function processing the data type is structured in
the same way Different fields have different
assurance on their
existence
Using type analysis we can verify we are safe and exhaustive
17
Modeling Trees with Types
squareTree(bt2); ==> { root: 4, left: { root: 9, left: { root: 16 } }, right: { root: 25, right: { root: 36 } } }
Being
exhaustive
resulted in
lots of
repeated code
18
Modeling Trees with Types By relaxing type checking and accepting undefined as a return value we can make the code shorter and more readable:
19
Modeling Trees with Types
squareTree2(bt)
{ root: 4, left: { root: 9, left: { root: 16, left: undefined, right: undefined }, right: undefined }, right: { root: 25, left: undefined, right: { root: 36, left: undefined, right: undefined } } }
Output:
20
Modeling Trees with Types Let us reflect on this version:
The expected values of type BinTree were extended to include undefined
We explicitly test for undefined as the first base case in the recursive function.
The recursive calls are now simplified as we can avoid the recursive calls with a value undefined
The return value has values marked explicitly as undefined - these are semantically equivalent to absent values - but in the syntax of the object, they still appear.
21
Modeling Trees with Types How can we eliminate the undefined in the output? Using JSON.stringify()
The two version correspond to different styles
undefined may complicate analysis
but is hard to avoid
22
Mutable Data Types in FP
Suppose we want to implement in FP a stack, which is mutable by nature?
push(x)
pop()
empty() Query. Does not mutate.
Mutate. And return a value.
23
Mutable Data Types in FP Let us separate to pure queries and pure mutators
push(x)
pop()
peek()
empty()
Mutators
Queries
This definition is still inherently procedural
The result maybe that even queries are
not deterministic
Can return different values on same calls
24
Mutable Data Types in FP Non-Functional Implementation
Relies on arrays being mutable
Generic
Queries. No mutations.
Constructor
Mutators
25
Mutable Data Types in FP Can a non-deterministic behavior of queries really occur?
Peek(s) on the same value s, returns different results
26
Mutable Data Types in FP Functional Implementation (not efficient)
Generic
Queries. No mutations.
Constructor
Return new copy
Cloning utility (shallow)
27
Mutable Data Types in FP Does it provides a deterministic behavior?
Yes! This implementation
is safe
But inefficient!
Using this implementation requires a change from the
client side: the interface
has a changed!
28
Mutable Data Types in FP What is the remedy?
Use efficient immutable libraries such as immutable-js by Facebook
29
Mutable Data Types in FP The immutablle-js library works well with JSON So we can e.g. construct a Stack for a string
30
Summary
Type definitions help the programmer structure the code that operates on complex values in a way that reflects the structure of the data type.
Programmers design and name types for sets of values that will be processed by the same set of functions.
Homogeneous array types encourage the programmer to consume them using the sequence interface (map, filter, reduce)
31
Summary Recursive types are processed by recursive functions othe recursive functions inspect the values according to the type definition
oand can determine the base case and the inductive case.
Mutable data types can be modeled in a Functional Programming style by making sure commands are written as constructors which return a new version of the values (instead of mutating an existing value).
Disjoint types and Disjoint Unions enable the definition of uniform functional interfaces over types of values that are not structurally similar.