What are semantics of OOP in terms of operations that take arguments (other objects)?
A simple example would be an addition operation (or equals method for Java programmers out there).
I have an object that extends an integer and want to add another object that also extends an integer. One of them might be a complex number. The other could be tagged with display colour. Should addition retain both properties?
Are there any restrictions in OOP that limit scope of possible the results in general?
There is no a priori restriction and the decision of the "generality" of the operation should be the higher that make sense in your project.
For instance
int + float -> float : 1 + 3.14 -> 3.14
int + fraction -> fraction : 1 + 1/3 -> 4/3
fraction + float -> float : 1/3 + 3.14 -> 3.47333333333
int + polynomial -> polynomial: 1 + (x^2 + x + 2) -> x^2 + x + 3
and so on.
Of course, the receiver doesn't have to know how to operate with all kinds of arguments, and it will probably use double dispatching or some other technique to extend the operation as new argument types present.
Related
The List type in Lean 4's prelude has a lot of nice goodies implemented, e.g. List.map, List.join, etc.
A classic example in dependently-typed languages is Vector a n where a is the type of the elements of the container, and n is the length. This allows you to do nice things like write a function concat (u : Vector a m) (v : Vector a n) : Vector a (m + n) whose type signature guarantees that the function returns a vector of the expected length.
Following a comment on a previous answer I'd like to write a Vector type as a Subtype of List, as a first step towards getting these methods for a sized container. But I'm new to Lean, and I don't exactly understand how this works. Subtype takes a predicate a -> Prop, which appears to work a bit like a filter on the parent type, which in this case is a := List. But all lists are valid vectors, so it doesn't seem like this is much use. The predicate should always return true, no?
My question is:
How can I use Subtype to get a subtype of List whose length is encoded in its type? And as a follow-up, how can I construct an element of this type from an existing List?
You're right that all lists are valid vectors, but the predicate is exactly how to specify that the Vector has a certain number of elements.
def Vec (n : Nat) (a : Type) := { ls : List a // ls.length = n }
def myVec : Vec 3 Nat := ⟨[1, 2, 3], rfl⟩
This is a question about how I should organize my F# code. I hope it is not in violation of SO rules.
I have dozens of source files (names terminating in .fs) in my project. Each file contains a module. In some of these files/modules I define only functions. In others I define functions and other values (not functions).
The last file in the Solution Explorer (Visual Studio) is Program.fs which actually contains very little code. Most calculations have been done "above" it.
I am considering moving the non-function values declared in the other modules to Program.fs. These are the advantages and disadvantages I see from this change:
Advantages:
1) A better view of program flow.
2) Easier to select all code above a certain line and send it for execution in FSI.
3) Slightly easier to search for those values in the editor.
4) Possibly easier to debug by putting breakpoints on the lines where values are declared.
Disadvantages:
1) Program.fs could become large and unwieldy.
2) Loss of modularity.
3) After implementing the changes, if the calculation of value y in module B depends on value x in module A "above" it then I can no longer have y as a value, it must be declared as a function of x. Similarly if a function declaration in module B depends on a value in module A I must add a parameter to the function definition.
Below are two examples of the same small program created under the two alternative methods. Which of the two is better in general?
// ///////////////// Values in modules \\\\\\\\\\\\\\\\\\\\
// File A.fs
module A
let i = 1
let add x y : float = x + y
// File B.fs
module B
let sqr z = z * z + float i
let x = sqr 99.9
// File Program.fs
open A
open B
let y =
add (float i) x
|> sqr
printfn "%f" y
[<EntryPoint>]
let main argv =
printfn "%A" argv
0 // return an integer exit code
// This is the calculated value for y: 99640524.640100
// ///////////////// Values in Program.fs \\\\\\\\\\\\\\\\\\\\
// File A.fs
module A
let add x y : float = x + y
// File B.fs
module B
open A
let sqr i z = z * z + float i // notice the additional parameter
//File Program.fs
open A
open B
let i = 1
let x = sqr i 99.9
let y =
add (float i) x
|> sqr i
printfn "%f" y
[<EntryPoint>]
let main argv =
printfn "%A" argv
0 // return an integer exit code
// This is the calculated value for y: 99640524.640100
As you presented it, the second version (with values moved to Main) is better imho. You pretty much nailed it with the #1 advantage and it's a really big one. As for the disadvantages you listed:
Large main: Yeah, depends on how much stuff we're talking, worst case you could keep the values in yet another module used just by main and just for values. Think "Config module"
Loss of modularity: I can't see
why. If anything it increases the modularity? Your main does not
depend on module X having some value, it provides it. You can then swap the module with another satisfying the same interface and not care about ripple effect it could have on other modules. If you have a large hierarchy of modules you could look into representing it in your main as per dependency inversion principle - it would take some work but the good news is that in functional languages you don't need IoC containers, partial application does the job
If module B depends on a value existing in module A it isn't very modular to begin with, is it? It's a good thing that you will have to change it into a function - it will explicitly say what is now implicit
Note that I'm writing this from my mostly OOP experience, so in functional programming some of it may be not applicable
I've been experimenting with Idris and it seems like it should be simple to specify some sort of type for representing all numbers between two different numbers, e.g. NumRange 5 10 is the type of all numbers between 5 and 10. I'd like to include doubles/floats, but a type for doing the same with integers would be equally useful. How would I go about doing this?
In practice, you may do better to simply check the bounds as needed, but you can certainly write a data type to enforce such a property.
One straightforward way to do it is like this:
data Range : Ord a => a -> a -> Type where
MkRange : Ord a => (x,y,z : a) -> (x >= y && (x <= z) = True) -> Range y z
I've written it generically over the Ord typeclass, though you may need to specialize it. The range requirement is expressed as an equation, so you simply supply a Refl when constructing it, and the property will then be checked. For example: MkRange 3 0 10 Refl : Range 0 10. One disadvantage of something like this is the inconvenience of having to extract the contained value. And of course if you want to construct an instance programmatically you'll need to supply the proofs that the bounds are indeed satisfied, or else do it in some context that allows for failure, like Maybe.
We can write a more elegant example for Nats without much trouble, since for them we already have a library data type to represent comparison proofs. In particular LTE, representing less-than-or-equal-to.
data InRange : Nat -> Nat -> Type where
IsInRange : (x : Nat) -> LTE n x -> LTE x m -> InRange n m
Now this data type nicely encapsulates a proof that n ≤ x ≤ m. It would be overkill for many casual applications, but it certainly shows how you might use dependent types for this purpose.
I've been programming for a long time (too long, actually), but I'm really struggling to get a handle on the terms "Free Variables" and "Bound Variables".
Most of the "explanations" I've found online start by talking about topics like Lambda calculus and Formal logic, or Axiomatic Semantics. which makes me want to reach for my revolver.
Can someone explain these two terms, ideally from an implementation perspective. Can they exist in compiled languages, and what low-level code do they translate to?
A free variable is a variable used in some function that its value depends on the context where the function is invoked, called or used. For example, in math terms, z is a free variable because is not bounded to any parameter. x is a bounded variable:
f(x) = x * z
In programming languages terms, a free variable is determined dynamically at run time searching the name of the variable backwards on the function call stack.
A bounded variable evaluation does not depend on the context of the function call. This is the most common modern programming languages variable type. Local variables, global variables and parameters are all bounded variables.
A free variable is somewhat similar to the "pass by name" convention of some ancient programming languages.
Let's say you have a function f that just prints some variable:
def f():
print(X)
This is Python. While X is not a local variable, its value follows the Python convention: it searches upwards on the chain of the blocks where the function is defined until it reaches the top level module.
Since in Python the value of X is determined by the function declaration context, we say that X is a bounded variable.
Hypothetically, if X were a free variable, this should print 10:
X = 2
def f():
print(X)
def g():
# X is a local variable to g, shadowing the global X
X = 10
f()
In Python, this code prints 2 because both X variables are bounded. The local X variable on g is bounded as a local variable, and the one on f is bounded to the global X.
Implementation
The implementation of a programming language with free variables needs to take care the context on where each function is called, and for every free variable use some reflection to find which variable to use.
The value of a free variable can not be generally determined at compile time, since is heavily determined by the run time flow and the call stack.
Whether a variable is free or bound is relative; it depends on the fragment of code you are looking at.
In this fragment, x is bound:
function(x) {return x + x;};
And here, x occurs free:
return x + x;
In other words, freeness is a property of the context. You don't say "x is a free variable" or "x is a bound variable," but instead identify the context you are talking about: "x is free in the expression E." For this reason, the same variable x can be either free or bound depending on which fragment of code you are talking about. If the fragment contains the variable's binding site (for example, it is listed in the function arguments) then it is bound, if not, it is free.
Where the free/bound distinction is important from an implementation perspective is when you are implementing how variable substitution works (e.g. what happens when you apply arguments to a function.) Consider the evaluation steps:
(function(x) {return x + x;})(3);
=> 3 + 3
=> 6
This works fine because x is free in the body of the function. If x was bound in the body of the function, however, our evaluation would need to be careful:
(function(x) {return (function(x){return x * 2;})(x + x);})(3);
=> (function(x){return x * 2;})(3 + 3); // careful to leave this x alone for now!
=> (function(x){return x * 2;})(6);
=> 6 * 2
=> 12
If our implementation didn't check for bound occurrences, it could have replaced the bound x for 3 and given us the wrong answer:
(function(x) {return (function(x){return x * 2;})(x + x);})(3);
=> (function(x){return 3 * 2;})(3 + 3); // Bad! We substituted for a bound x!
=> (function(x){return 3 * 2;})(6);
=> 3 * 2
=> 6
Also, it should be clarified that free vs. bound is a property of the syntax (i.e. the code itself), not a property of how a the code is evaluated at run-time. vz0 talks about dynamically scoped variables, which are somewhat related to, but not synonymous with, free variables. As vz0 correctly describes, dynamic variable scope is a language feature that allows expressions that contains free variables to be evaluated by looking at the run-time call-stack to find the value of a variable that shares the same name. However, It still makes sense to talk about free occurrences of variables in languages that don't allow dynamic scope: you would just get an error (like "x is not defined") if you were to try to evaluate an such expression in these languages.
And I can't restrain myself: I hope one day you can find the strength to put your revolvers away when people mention lambda calculus! Lambda calculus is a good tool for thinking about variables and bindings because it is an extremely minimal programming language that supports variables and substitution and nothing else. Real-world programming languages contain a lot of other junk (like dynamic scope, for example) that obscures the essence.
Is it possible to override the + operator in smalltalk to accept two params? i.e., I need to also pass in the units for my custom class. Something like:
Number subclass: #NumberWithUnits
instanceVariableNames: 'myName unitTracker'
classVariableNames: ''
poolDictionaries: ''
category: 'hw3'
+ aNumber theUnits
unitTracker adjustUnits: theUnits.
^super + aNumber
Or is there an easier way to do this that I haven't considered?
Additional problem description:
(NumberWithUnits value: 3 unit: #seconds) should give you a NumberWithUnits that represents 3 seconds. But you should also be able to write 3 sec and that should evaluate to a NumberWithUnits (seconds is already taken in Pharo 2.0). The way to do this is to add a sec method to Number, which basically returns (NumberWithUnits value: self unit: #seconds). You can add methods for meters and elephants as well. Then you could write an expression 3 elephants / (1 sec sec) and it would return the right thing. Write a test for it to be sure!
What you're missing is the order of evaluation/precedence in Smalltalk. It's actually quite a bit simpler than in most other languages:
explicit parentheses ()
unary
binary
keyword
assignment :=
So, you can implement a unary method on Number which gets evaluated before the binary +. A simple example is Number>>negated, which is Smalltalk's version of the unary minus.
At least in Squeak/Pharo (all I've got handy at the moment), date arithmetic is already implemented similarly. Look at Number>>minutes, for example, so you can evaluate things like 5 hours - 3 minutes, which returns a Duration of 0:04:57:00.
I think a more idiomatic way to do this would be to construct a second NumberWithUnits, and then add that.
Then inside your + method you need to reconcile the units of the two things being added, then add their magnitudes.
So something like
a := Measure new: 2 #m
b := Measure new: 10 #mm
a + b
Measure class [
+ other [
"TODO: check/convert units here"
resultMagnitude := (a magnitude) + (b magnitude).
combinedUnits := (a units) * (b units).
^Measure new resultMagnitude units: combinedUnits.
]
]
See also for example the GNU Smalltalk example of operator overloading.