Inheritance to extend a data structure in Haskell - oop

A C++ programmer trying to learn Haskell here. Please excuse this probably easy question. I want to translate a program that represents 3D shapes. In C++ I have something like:
class Shape {
public:
std::string name;
Vector3d position;
};
class Sphere : public Shape {
public:
float radius;
};
class Prism : public Shape {
public:
float width, height, depth;
};
I am trying to translate this to Haskell (using records?) so that I can have some functions which know how to operate on a Shape (like accessing its name and position), and others than know only how to operate on spheres, like calculating something based on its position and radius.
In C++ a member function could just access these parameters but I'm having a hard time figuring out how to do this in Haskell with records, or type classes, or whatever.
Thanks.

The straight-forward translation.
type Vector3D = (Double, Double, Double)
class Shape shape where
name :: shape -> String
position :: shape -> Vector3D
data Sphere = Sphere {
sphereName :: String,
spherePosition :: Vector3D,
sphereRadius :: Double
}
data Prism = Prism {
prismName :: String,
prismPosition :: Vector3D,
prismDimensions :: Vector3D
}
instance Shape Sphere where
name = sphereName
position = spherePosition
instance Shape Prism where
name = prismName
position = prismPosition
You usually wouldn't do this, though; it's repetitious and polymorphic lists require language extensions.
Instead, sticking them into a single closed datatype is probably the first solution you should go for.
type Vector3D = (Double, Double, Double)
data Shape
= Sphere { name :: String, position :: Vector3D, radius :: Double }
| Prism { name :: String, position :: Vector3D, dimensions :: Vector3D }
You can certainly simulate multiple levels of inheritance by creating more typeclasses:
class (Shape shape) => Prism shape where
dimensions :: Vector3D
data RectangularPrism = ...
data TriangularPrism = ...
instance Prism RectangularPrism where ...
instance Prism TriangularPrism where ...
You can also simulate it by embedding datatypes.
type Vector3D = (Double, Double, Double)
data Shape = Shape { name :: String, position :: Vector3D }
data Sphere = Sphere { sphereToShape :: Shape, radius :: Double }
newSphere :: Vector3D -> Double -> Shape
newSphere = Sphere . Shape "Sphere"
data Prism = Prism { prismToShape :: Shape, dimensions :: Vector3D }
data RectangularPrism = RectangularPrism { rectangularPrismToPrism :: Prism }
newRectangularPrism :: Vector3D -> Vector3D -> RectangularPrism
newRectangularPrism = (.) RectangularPrism . Prism . Shape "RectangularPrism"
data TriangularPrism = TriangularPrism { triangularPrismToPrism :: Prism }
newTriangularPrism :: Vector3D -> Vector3D -> TriangularPrism
newTriangularPrism = (.) TriangularPrism . Prism . Shape "TriangularPrism"
But simulating OO in Haskell is not anywhere near as satisfying as actually thinking in a Haskellish way. What are you trying to do?
(Also note that all of these solutions only permit upcasts, downcasting is unsafe and disallowed.)

Contrary to the trend of discouraging the use of typeclasses, I'd recommend (as you're learning) to explore both a solution without typeclasses and one with, to get a feeling for the different tradeoffs of the various approaches.
The "single closed datatype" solution is certainly more "functional" than typeclasses. It implies that your list of shapes is "fixed" by your shape module and not extensible with new shapes from the outside. It is still easy to add new functions operating on the shapes.
You have a slight inconvenience here if you have a function that operates only on a single shape type because you give up the static compiler check that the shape passed in is correct for the function (see Nathan's example). If you have a lot of these partial functions that work only on one constructor of your datatype, I would reconsider the approach.
For a typeclass solution, I'd personally rather not mirror the shape class hierarchy but create type classes for "things with a surface area", "things with a volume", "things with a radius", ...
This allows you to write functions that take particular kinds of shapes, say spheres, only (as each shape is its own type), but you can't write a function that takes "any shape" and then distinguishes the various concrete kinds of shapes.

Like Nathan said, modelling datatypes is completely different in Haskell from C++. You could consider the following approach:
data Shape = Shape { name :: String, position :: Vector3d }
data Sphere = Sphere { sphereShape :: Shape, radius :: Float }
data Prism = Prism { prismShape :: Shape, width :: Float, height :: Float, depth :: Float }
In other words, model references to super classes as extra fields in your datatype. It easily extends to longer inheritance chains.
Don't use type classes, like ephemient suggests. These are used for overloading functions and that is not the issue here at all: your question concerns the modelling of data, not behaviour.
Hope this helps!

A simple translation breaks out the part that varies but avoids typeclasses:
type Vector3D = (Float,Float,Float)
data Body = Prism Vector3D | Sphere Double
radius (Prism position) = -- code here
radius (Sphere r) = r
then
data Shape = Shape {
name :: String,
position :: Vector3D,
body :: Body
}
shapeOnly (Shape _ pos _) = -- code here
both = radius . body
sphereOnly (Shape _ _ (Sphere radius)) = -- code here
sphereOnly _ = error "Not a sphere"
This is not a really easy question. Data structure design is very different between C++ and Haskell, so I bet that most people coming from an OO language ask the same thing.
Unfortunately, the best way to learn is by doing; your best bet is to try it on a case-by-case basis until you learn how things work in Haskell.
My answer is pretty simple, but it doesn't deal well with the case where a single C++ subclass has methods that the others don't. It throws a runtime error and requires extra code to boot. You also have to decide whether the "subclass" module decides whether to throw the error or the "superclass" module.

Related

Specifying a function with templates that takes and returns an arbitrary class

I'm interested in defining a function that given a class variable, generates and a new instance of the class object with a randomly selected member attribute mutated.
Context: Consider an instance, circle1, of some class, Circle, has attributes color and radius. These attributes are assigned values of red and 5, respectively. The function in question, mutate, must accept circle1 as an argument, but reject non-class arguments.
For other data types, templates provide an answer in this context. That is, templates may be used to specify generic instances of functions that can accept arguments of multiple types.
How can a generic function that accepts (and returns) an instance of any class be defined using templates?
In general, if you need to restrict what a template can take, you use template constraints. e.g.
import std.traits : isIntegral;
auto foo(T)(T t)
if(isIntegeral!T)
{
...
}
or
import std.functional : binaryFun;
auto foo(alias pred, T, U)(T t, U u)
if(is(typeof(binaryFun!pred(t, u.bar())) == bool)
{
...
}
As long the condition can be checked at compile time, you can test pretty much anything. And it can be used for function overloading as well (e.g. std.algorithm.searching.find has quite a few overloads all of which are differentiated by template constraint). The built-in __traits, the eponymous templates in std.traits, and is expressions provide quite a few tools for testing stuff at compile time and then using that information in template constraints or static if conditions.
If you specifically want to test whether something is a class, then use an is expression with == class. e.g.
auto foo(T)(T t)
if(is(T == class))
{
...
}
In general though, you'll probably want to use more specific conditions such as __traits(compiles, MyType result = t.foo(22)) or is(typeof(t.foo(22)) == MyType). So, you could have something like
auto mutate(T)(T t)
if(is(T == class) &&
__traits(compiles, t.color = red) &&
__traits(compiles, t.radius = 5))
{
...
}
If the condition is something that you want to reuse, then it can make sense to create an eponymous template - which is what's done in Phobos in places like std.range.primitives and std.range.traits. For instance, to test for an input range, std.range.primitives.isInputRange looks something like
template isInputRange(R)
{
enum bool isInputRange = is(typeof(
{
R r = R.init; // can define a range object
if (r.empty) {} // can test for empty
r.popFront(); // can invoke popFront()
auto h = r.front; // can get the front of the range
}));
}
Then code that requires an input range can use that. So, lots of functions in Phobos have stuff like
auto foo(R)(R range)
if(isInputRange!R)
{
...
}
A more concrete example would be this overload of find:
InputRange find(alias pred = "a == b", InputRange, Element)
(InputRange haystack, Element needle)
if(isInputRange!InputRange &&
is(typeof(binaryFun!pred(haystack.front, needle)) : bool))
{
...
}
Ali Çehreli's book, Programming in D, has several relevant chapters, including:
http://ddili.org/ders/d.en/templates.html
http://ddili.org/ders/d.en/cond_comp.html
http://ddili.org/ders/d.en/is_expr.html
http://ddili.org/ders/d.en/templates_more.html

Go "polymorphism"

People are saying, Go is not an OO (Object Oriented) language; don't use OO terms on Go. OK, let me describe what I am able to do with OO --
With an OO language, I can make different animals say different things based on their classes:
cat.Say() // miao
sheep.Say() // bahh
cow.Say() // moo
The same is getting the Area() from Shapes.
However, this go demo code made me believe that it is impossible. Included below as Exhibit#1.
Then today, I found this go demo code, which makes it entirely possible. Included below as Exhibit#2.
So my question is, what's fundamentally different between the two, that makes the first one wrong and second one correct?
How to make the first one "works"?
Exhibit#1:
// Credits: hutch
// https://groups.google.com/d/msg/golang-nuts/N4MBApd09M8/0ij9yGHK_8EJ
////////////////////////////////////////////////////////////////////////////
/*
https://groups.google.com/d/msg/golang-nuts/N4MBApd09M8/tOO5ZXtwbhYJ
LRN:
Subtype polymorphism: Not applicable (Go doesn't have subtyping).
Although if you embed a struct A implementing interface X into a struct B,
struct B will implement interface X, and can be used instead of struct A in
places where struct A is expected. So, kind of yes.
Robert Johnstone:
interfaces behave similarly to virtual functions, but they are not identical. See the (following) example program by hutch.
*/
package main
import "fmt"
type A struct {
astring string
}
type B struct {
A
bstring string
}
type Funny interface {
strange()
str() string
}
func (this *A) strange() {
fmt.Printf("my string is %q\n", this.str())
}
func (this *A) str() string {
return this.astring
}
func (this *B) str() string {
return this.bstring
}
func main() {
b := new(B)
b.A.astring = "this is an A string"
b.bstring = "this is a B string"
b.strange()
// Output: my string is "this is an A string"
// Many people familiar with OO (and unfamiliar with Go) will be quite
// surprised at the output of that program.
}
Exhibit#2:
// Credits: https://play.golang.org/p/Zn7TjiFQik
////////////////////////////////////////////////////////////////////////////
/*
Problem (From Polymorphism-Subtype.go):
https://groups.google.com/d/msg/golang-nuts/N4MBApd09M8/tOO5ZXtwbhYJ
LRN: Subtype polymorphism: Not applicable (Go doesn't have subtyping).
Goal:
This is to demo that "polymorphism" is still doable in Go.
*/
package main
import (
"fmt"
)
type Shape interface {
Area() float32
}
type Point struct {
x float32
y float32
}
// Make sure the structs are different sizes so we're sure it'll work with
// all sorts of types
type Circle struct {
center Point
radius float32
}
func (c Circle) Area() float32 {
return 3.1415 * c.radius * c.radius
}
type Rectangle struct {
ul Point
lr Point
}
func (r Rectangle) Area() float32 {
xDiff := r.lr.x - r.ul.x
yDiff := r.ul.y - r.lr.y
return xDiff * yDiff
}
func main() {
mtDict := make(map[string]Shape)
// No problem storing different custom types in the multitype dict
mtDict["circ"] = Circle{Point{3.0, 3.0}, 2.0}
mtDict["rect"] = Rectangle{Point{2.0, 4.0}, Point{4.0, 2.0}}
for k, v := range mtDict {
fmt.Printf("[%v] [%0.2f]\n", k, v.Area())
}
}
/*
$ go run Polymorphism-Shape.go
[circ] [12.57]
[rect] [4.00]
*/
Your two exhibits are doing different things.
In the first one, B has A embedded in it, and B doesn't implement the strange() method itself, so when you call b.strange(), you get the implementation of strange() defined for A. The receiver (this) of the strange method is b.A, not b, so the value b.A.astring is printed. If you wanted strange to print bstring, you would have to define strange for B.
This points out one of the differences between Go and other OO languages: embedding A within B does not mean that B is a "subclass" of A, so an object of type B cannot be used where an object of type A is expected. However, since B inherits the fields and methods of A, any interface that's implemented by A is also implemented by B, and, unless those methods are defined specifically for B, they operate on the A within B, not B itself.
In the second exhibit, you have the Shape interface which is implemented by the types Circle and Rectangle. The element type of your map is Shape, so any type that implements that interface can be an element in the map. When working with a value of an interface type as you are doing in the loop, you can call any method defined in the interface on the value, and the definition corresponding to the actual type of the value will be called.
First of all I would like to discuss the "impossible" part.
import "fmt"
type Animal interface {
Say() string
}
type Cat struct {}
func (cat Cat) Say() string {
return "miao"
}
type Sheep struct {}
func (sheep Sheep) Say() string {
return "bahh"
}
type Cow struct {}
func (cow Cow) Say() string {
return "moo"
}
func main() {
cat := Cat{}
sheep := Sheep{}
cow := Cow{}
fmt.Println(cat.Say())
fmt.Println(sheep.Say())
fmt.Println(cow.Say())
}
This will work exactly as you would expect. So there is a polymorphism in terms of "different structs responding differently to same method".
The intention of Exhibit#1 demonstrates that what Go does is actually similar to Java castings before #Overrides.
Just add the following method to the first example and see how that will work:
func (this B) strange() {
fmt.Printf("my string is %q\n", this.str())
}

What's the most efficient way to access specific, related member variables via a single function call?

I'm trying to utilize a single function call to access multiple data members of a class called "Data." In this particular instance, I'm accessing the data fed to the class from a physical gyroscope sensor. This is what I've got:
template <typename T>
T Data<T>::getGyro_euler(char c)
{
switch (c)
{
case 'x': return m_eulerX;
case 'y': return m_eulerY;
case 'z': return m_eulerZ;
default: return 0;
}
}
The data type this function uses is always either a float or a double.
Performance is more important than clarity in this case, as this is running on an already-overburdened Arduino that needs to perform mission-critical tasks, but something just feels kind of dirty about manually passing a character to a function to get a certain variable out of it.
I've got a number of functions like this with quite a number of variables that need to be passed, so having a getter function for each variable would get quite hefty in the code.
Is there a more efficient way of doing this? Is there a better, more clear way to accomplish the same thing without sacrificing performance?
You probably named your class Data for a reason : it is (or at least should be) plain data. Don't make it a class, make it a structure, or better yet, a POD type.
That way you can access any member you want just by typing its name after a dot : data.eulerX. As a bonus, you get no performance issue, more clarity and better readability.
In my opinion your approach is too complicated for the problem you describe.
As others mentioned in the comment accessing fields would be sufficient. You could choose to group together fields that are meant to be used together to improve the readability of your code using for instance std::tuple.
Below an incomplete example (as I don't know how the data is collected).
The performance cost is not related to the number of line of code, but more to the complexity the code involve (for instance here there won't be a need for a switch occuring at runtime); for the trivial types (double) described in the question I don't think it will be an issue.
#include <tuple>
struct giroData
{
private:
double sensorX;
double sensorY;
double sensorZ;
// or
std::tuple<double, double, double> sensor;
public :
double getSensorX() { return sensorX; }
double getSensorY() { return sensorY; }
double getSensorZ() { return sensorZ; }
std::tuple<double, double, double> getSensor() { return sensor; }
};
int main()
{
double x, y, z;
giroData d;
x = d.getSensorX();
y = d.getSensorY();
z = d.getSensorZ();
// or
std::tie(x, y, z) = d.getSensor();
}

How to dismember structure data and operators?

I want to build algebraic system, so I need a carrier, which is basically some data type, and a bunch of operators over that type. It is natural for algebras to differ in signature meaning the same type might have different set of operators with the same notation.
Say I have a vector type. Normally I would use euclidean metric and norm for it, so I import vector, euclidean, where vector contains data declaration for vector type, but all the overloaded operators for the same vector go to euclidean. Then when I want to work with riemanian space I simply import vector, riemanian and get a completely different algebra with the same interface.
I know, this can be achieved in object paradigm via inheritance, but maybe it is possible to do that with plain modules? All I need is to declare data in one module and operators in other all for the same structure.
Two possibilities come to mind. One is using UFCS, defining named functions (it won't work for the operator overloads) in other modules that take the type as the first parameter, then are callable with dot syntax (forgive me if I mess up the math here):
module myvector;
struct vector {
float x;
float y;
}
module myvectormath;
import myvector;
vector add(vector lhs, vector rhs) {
// inside, it is just a regular function
vector result;
result.x = lhs.x + rhs.x;
result.y = lhs.y + rhs.y;
return result;
}
usage:
import myvector;
import myvectormath;
// but it can be called with dot notation
vector a = vector(0,0).add(vector(5, 5));
Another possible way is to put the data in a struct or a mixin template, then make the math by putting that in another struct with the needed functions:
// data definition
module myvector;
// the data will be an external named type, so we can pass it on more easily - will help interop
struct VectorData {
float x;
float y;
}
// and this provides the stuff to get our other types started
mixin template vector_payload() {
// constructors for easy initialization
this(float x, float y) {
_data.x = x;
_data.y = y;
}
this(VectorData d) {
_data = d;
}
// storing our data
VectorData _data;
// alias this is a feature that provides a bit of controlled implicit casting..
alias _data this;
}
// math module #1
module myvectormath;
import myvector;
struct vector {
// mixin all the stuff from above, so we get those ctors, the data, etc.
mixin vector_payload!();
// and add our methods, including full operator overloading
vector opBinary(string op:"+")(vector rhs) {
vector result;
result.x = this.x + rhs.x;
result.y = this.y + rhs.y;
return result;
}
}
// math module #2
module myvectormath2;
import myvector;
struct vector {
// again, mix it in
mixin vector_payload!();
// and add our methods
vector opBinary(string op:"+")(vector rhs) {
vector result;
// this one has horribly broken math lol
result.x = this.x - rhs.x;
result.y = this.y - rhs.y;
return result;
}
}
// usage
import myvectormath;
// OR
//import myvectormath2;
void main() {
vector a = vector(0, 0) + vector(5, 5);
import std.stdio;
writeln(a);
}
In the usage module, if you just replace imports, the rest of the code remains unmodified. What happens though if you want to use both modules at once and intermix them? That's where the inner struct _Data, the constructor taking it, and alias this magic comes in. First, we'll import both and see what happens:
test32.d(23): Error: myvectormath.vector at test324.d(4) conflicts with myvectormath2.vector at test322.d(4)
So, first, we want to disambiguate the name. There's all kinds of ways to do this, you can learn more in the import section of the D docs: http://dlang.org/module.html#Import
For now, I'm going to just use the fully qualified name.
// usage
import myvectormath;
import myvectormath2;
void main() {
// specify the kind we want to use here...
myvectormath.vector a = myvectormath.vector(0, 0) + myvectormath.vector(5, 5);
import std.stdio;
writeln(a); // and we get a result of 0, 5, so it used the addition version correctly
}
How can we easily move them around internally? Let's make a function that uses version #2:
void somethingWithMath2(myvectormath2.vector vec) {
// whatever
}
It will complain if you pass the variable "a" to it because it is myvectormath.vector, and this is myvectormath2.
test32.d(27): Error: function test32.somethingWithMath2 (vector a) is not callable using argument types (vector)
But, we can pretty easily convert them thanks to the external data struct, the ctor, and alias this in the mixin template:
somethingWithMath2(myvectormath2.vector(a));
Compiles! The way that works under the hood is myvectormath2.vector has two constructors: (float, float) and (VectorData). Neither of them match the type of a, so next it tries a's alias this... which is VectorData. So it implicitly converts and then matches the VectorData ctor.
You could also just pass the data around:
import myvector;
void somethingWithMath2(VectorData a_in) {
// to do math on it, we construct the kind of vectormath we're interested in:
auto a = myvectormath2.vector(a_in);
// and use it
}
And then call it this way:
// will implicitly convert any of the sub vectormath types to the base data so this just works
somethingWithMath2(a);
Passing around the data would probably be most nice, since then the caller doesn't need to know what kind of stuff you'll be doing with it.
The constructor it uses here is trivial by the way, and shouldn't incur significant runtime loss (possibly none at all if the compiler switch is set to inline it; this is basically just a reinterpret_cast; the data representation is identical).
Note that it will not let you add myvectormath2.vector + myvectormath.vector, that will be a type mismatch. But if you do want to allow that, all you have to do is change the overloaded operator to accept VectorData instead of one of the math types! Then it will implicitly convert and you have the same data to work on. Think of VectorData as being a base class in OOP terms.
I think that covers the bases, let me know if you have any further questions.

How can I hide methods in F#?

I am currently implementing a Spec framework in F# and I want to hide the Equals, GetHashCode etc. methods on my should type, so that the API is not cluttered with these.
I know in C# it is done by making the class implement an interface like this:
using System;
using System.ComponentModel;
public interface IFluentInterface
{
[EditorBrowsable(EditorBrowsableState.Never)]
bool Equals(object other);
[EditorBrowsable(EditorBrowsableState.Never)]
string ToString();
[EditorBrowsable(EditorBrowsableState.Never)]
int GetHashCode();
[EditorBrowsable(EditorBrowsableState.Never)]
Type GetType();
}
I tried doing the same in F#:
type IFluentInterface = interface
[<EditorBrowsable(EditorBrowsableState.Never)>]
abstract Equals : (obj) -> bool
[<EditorBrowsable(EditorBrowsableState.Never)>]
abstract ToString: unit -> string
[<EditorBrowsable(EditorBrowsableState.Never)>]
abstract GetHashCode: unit -> int
[<EditorBrowsable(EditorBrowsableState.Never)>]
abstract GetType : unit -> Type
end
Implemented it in my type:
interface IFluentInterface with
member x.Equals(other) = x.Equals(other)
member x.ToString() = x.ToString()
member x.GetHashCode() = x.GetHashCode()
member x.GetType() = x.GetType()
but without success.
I also tried to override the methods in my type and adding the attribute that way, but that didn't do the trick either.
So the question remains, how can I clean up my API ?
Edit:
Thanks to the help (see below) I was able to solve my problem.
In summary, .Equals and .GetHashCode can be hidden via [<NoEquality>] [<NoComparison>] but that will also change the semantics.
The hiding via EditorBrowsable attributes does not work.
The only way to have a clean API and still be able to overload methods is to make these method members static.
The resulting class can be found by browsing inside my project FSharpSpec.
The type in question can be found here.
Thanks to everyone who helped me solve this problem.
Cheers ...
Alternatively, you could design the library using an alternative style using functions enclosed in a module. This is the usual way for writing functional code in F# and then you won't need to hide any standard .NET methods. To complete the example given by 'kvb', here is an example of object-oriented solution:
type MyNum(n:int) =
member x.Add(m) = MyNum(n+m)
member x.Mul(m) = MyNum(n*m)
let n = new MyNum(1)
n.Add(2).Mul(10) // 'ToString' shows in the IntelliSense
The functional way of writing the code might look like this:
type Num = Num of int
module MyNum =
let create n = Num n
let add m (Num n) = Num (m + n)
let mul m (Num n) = Num (m * n)
MyNum.create 1 |> MyNum.add 2 |> MyNum.mul 10
If you type MyNum., the F# IntelliSense will show the functions defined in the module, so you won't see any noise in this case.
Repeating my answer from
http://cs.hubfs.net/forums/thread/13317.aspx
In F# you can disallow Equals & GetHashCode (and remove them from intellisense) by annotating the type with the NoEquality and NoComparison attributes, as shown below. User-defined methods can also be hidden from the intellisense list via the Obsolete attribute or the CompilerMessage attribute with IsHidden=true. There is no way to hide the System.Object methods GetType and ToString from the F# intellisense.
[<NoEquality; NoComparison>]
type Foo() =
member x.Bar() = ()
member x.Qux() = ()
[<System.Obsolete>]
member x.HideMe() = ()
[<CompilerMessage("A warning message",99999,IsError=false,IsHidden=true)>]
member x.WarnMe() = ()
let foo = new Foo()
foo. // see intellisense here
I don't think that there is any way to do that in F# in general. In the particular case of .Equals and .GetHashCode, you can make them unusable by putting a [<NoEquality>] attribute on your type, but this actually has a semantic effect in addition to hiding those methods.
EDIT
It might also be worth mentioning that fluent interfaces are rarely used in F#, since it's much more idiomatic to use combinators and pipelining instead. For instance, imagine that we want to create a way to create arithmetic expressions. Rather than
let x = Expressions.MakeExpr(1).Add(2).Mul(3).Add(4)
I think that most F# users would prefer to write
open Expressions
let x =
1
|> makeExpr
|> add 2
|> mul 3
|> add 4
With this style, there's no need to hide members because expressions get piped to combinators, rather than calling methods of an expression builder.