When there are many data types which have almost same structure, how can I implement without almost-duplicated codes?
Here is uncompilable code sample to explain the goal.
{-# LANGUAGE DuplicateRecordFields #-}
class Category a where
method :: a -> String
class ForB b where
...
class ForC c where
...
data A = A {someA :: String, ...}
data B1 = B1 {some :: Int, ...}
data B2 = B2 {some :: Int, ...}
...
data C1 = C1 {some :: Int, ...}
data C2 = C2 {some :: Int, ...}
...
instance Category A where
method (A x) = x
-- Cannot be compiled, but I want to write like this.
instance Category a where
method = show . some
instance ForB B1 where
....
instance ForC C1 where
....
main = do
let a = A "1"
b = B1 2
c = C1 3
print . method $ a
print . method $ b
print . method $ c
I understand that instance does not take type variable a like instance Something a but takes only real data type; Is there no polymorphic instance?
I've tried to solve this by introducing new classes like this, but could not figure it out.
I concerned phantom types or type families, but I could not find any solution.
I do not want to implement almost same code for each data types.
Please refer better explanation and sample to the goal on the background.
Is there any way to short-hand to implement polymorphic(?) instances without reducing data type or Template Haskell (lens,record,extensive package).
Background
I'm preparing series of sample code for transition from OOP to a functional approach.
Here is the simplified base code of the explanation.
And here is little improvement with DuplicateRecordFields.
You can see there are massive instance implements.
(Please do not ask me why do not combine LifeInfo, AnimalInfo and Human in a data type. This is one of the series to solve bunch of problems)
However, to implement Human, Elf, Pine and Rose, I write almost same instances for each. And there are some exceptions for LifeInfo, AnimalInfo, and PlantInfo.
Some points
Do not combine entry data types(A, B, and C) to a data type by using data constructor like data ABC = A {..} | B {..} | C {..}.
But when you can introduce a method for distinguishing each of them by type-checking or implement class-method like things, it will be good.
Please notice that there are classes ForB and ForC.
I'm avoiding Template Haskell and libraries using TH to solve this problem.
Related
I struggle with creating own instances for my datatypes.
I defined a type like:
data Breakfast = Egg | Sausage Int | Bread Breakfast deriving (Eq, Show)
and want it to be an instance of the class Ord. I want to compare it by some rules like: A Egg is as good as 2 Sausages etc.
I tried it like this:
instance Ord a => Ord (Breakfast) where
compare (Egg) (Sausage 2) = EQ
...
but I get the error:
Variable a occurs more often than in the instance head.
i tried another example and this works fine:
data Down a = Down a deriving (Eq, Show, Read)
instance Ord a => Ord (Down a) where
compare (Down x) (Down y) = y `compare` x
Hope you guys can help me whats wrong. Im very new to Haskell. Thanks
Just remove the constraint on your instance definition:
instance Ord Breakfast where
compare (Egg) (Sausage 2) = EQ
...
You had a constraint on a type variable a which wasn't used on the right-hand side (the instance head).
I generally find the set/get interface defined in hgsetget very useful for setting and getting multiple parameters at the same time. I recently found it was especially suited for object construction.
Example:
classdef testclass < hgsetget
properties
A
B
C
D
end
methods
function obj = testclass(varargin)
if ~isempty(varargin)
set(obj,varargin{:})
end
end
end
end
Usage:
>> a = testclass('A',1,'B',2)
a =
testclass handle
Properties:
A: 1
B: 2
C: []
D: []
Despite the slowness of this interface I'm really happy of the flexibility it provides.
What is more annoying for my application is that I obtain a handle class (by inheritance from hgsetget).
To circumvent this my first guess was to construct an abstract class with my set/get definition inside. Very simply written it gives:
classdef (Abstract) myAbstractClass
methods
function obj = set(obj,varargin)
for i = 1:2:length(varargin)
obj.(varargin{i}) = varargin{i+1};
end
end
function val = get(obj,varargin)
val = cell(length(varargin),1);
for i = 1:length(varargin)
val{i} = obj.(varargin{i});
end
end
end
end
and then set it as superclass for my test class
classdef testclass < myAbstractClass
properties
A
B
C
D
end
methods
function obj = testclass(varargin)
if ~isempty(varargin)
set(obj,varargin{:})
end
end
end
end
However I must misunderstand something in the construction mechanism because here is what happens:
>> a = testclass('A',1,'B',2)
ans =
testclass
Properties:
A: 1
B: 2
C: []
D: []
Methods, Superclasses
a =
testclass
Properties:
A: []
B: []
C: []
D: []
Methods, Superclasses
If somebody knows the reason of this behavior, I'm totally open to her/his explanations
Thank you in advance
JM
Overall your design looks good, but within your constructor method testclass, you need to write
obj = set(obj,varargin{:});
Because you are using a value class rather than a handle class, you need to retrieve the output of your set method, otherwise you'll have set the property of something, and then discarded it and returned a completely different (and empty) obj as output.
Also, you need to add a semi-colon after the call to set; otherwise it will display the intermediate something.
You may also want to revise your opinion of handle classes; they're really very natural to use (just my opinion, but more natural in an OO context than value-behaviour).
I have a wrapper template that looks like this:
#(first: Html, second:Html, third:Html)
<div class="wrapper">
#first
#second
#third
</div>
I have three templates I want to shuffle and place as first, second and third.
Let's name them: views.html.a, views.html.b, views.html.c.
The controller code:
val a = views.html.a
val b = views.html.b
val c = views.html.c
val list = Random.shuffle(List(a, b, c)) // Will use Random.shuffle here but it fails complication either way
Ok(views.html.wrapper(list(0)(), list(1)(), list(2)()))
The complication error:
play.templates.BaseScalaTemplate[play.api.templates.HtmlFormat.Appendable,play.templates.Format[play.api.templates.HtmlFormat.Appendable]] does not take parameters
It appears as entering the object to the List and getting it out tricks the compiler.
If I don't use list and do:
Ok(views.html.wrapper(a(), b(), c()))
it works as expected and renders the page.
I know I can move the random logic to the wrapper template but I prefer to understand / fix the current implementation and learn some Scala in the process.
Thanks
EDIT
After reading serejja's answer, I'll add complexity to the question since this better represents the problem I'm facing.
The three templates need to take a boolean so views.html.a looks like:
#(checkMe:Boolean)
<div ...
So I can't use parentheses before the shuffle. Only after the shuffle occur I wish to send true false true as the booleans.
Using this approach:
Ok(views.html.wrapper(list(0)(true), list(1)(false), list(2)(true)))
gives the following compilation error:
play.templates.BaseScalaTemplate[play.api.templates.Html,play.templates.Format[play.api.templates.Html]] with play.api.templates.Template1[Boolean,play.api.templates.Html] does not take parameters
You were almost there :)
val a = views.html.a()
val b = views.html.b()
val c = views.html.c()
Notice the parentheses. The type of a, b and c now is play.api.templates.HtmlFormat.Appendable instead of the one before.
Now you can pass it as you wanted:
Ok(views.html.wrapper(list(0), list(1), list(2)))
EDIT:
Ok, I cannot imagine what you are up to (so that the solution could be simplified if possible) but I found a workaround.
First, consider that views a, b and c are on the one level of hierarchy:
/ a
BaseScalaTemplate - b
\ c
For this solution to work, these views must have the same number of parameters (a(check: Boolean), b(check: Boolean), c(check: Boolean)) so that they make a List[play.templates.BaseScalaTemplate[play.api.templates.Html,play.templates.Format[play.api.templates.Html]]
with play.api.templates.Template1[Boolean,play.api.templates.Html]] (which means "a generic template with one Boolean parameter").
play.api.templates.Template1 has a method render which takes that parameter and returns you a HtmlFormat.Appendable (which I mentioned earlier).
Considering this your solution might be like this:
val a = views.html.a
val b = views.html.b
val c = views.html.c
val randomizedViews = Random.shuffle(List(a, b, c))
Ok(views.html.wrapper(list(0).render(true), list(1).render(false), list(2).render(true)))
Note that this solution is far from being perfect and I'd suggest you not to use it in real life. I dont think views are intended to be used this way.
Since I began programming in Scala, I gravitated towards what seems to be a natural coding style in this language, which is easiest to explain with a simple example:
val a = {
def f1(p : Int) = ...
def f2(p : Int) = ...
f1(12) * f2(100)
}
As you can see, the multiplication of the values, which, if you want to understand the code, is the first operation you should want to familiarize yourself with, is not to be found until the last line. Instead, you need to read through the pieces of the puzzle first (functions f1, f2) before you can see how they're actually arranged. For me, this makes the code harder to read. How are you dealing with this problem - or maybe you don't find it a problem at all?
One interesting approach might be to use the untyped macro proposal in macro-paradise to introduce a where binding, such that:
val a = (f1(12) * f2(100)) where {
def f1(x : Int) = x + 1
def f2(x : Int) = x + 2
}
gets rewritten to your code above. As I understand it, untyped macros would allow the non-existent identifiers f1 and f2 to exist past the pre-macro typecheck. I think the rewrite should be relatively simple, and then the second typecheck would catch any problems. However, I've never actually written any macros, so it's possible there's something about this which would fail!
If it were possible, I think it would be quite a nice form to have (and rewriting would solve problems with execution order) - if I get some time I may have a stab at writing it!
Edit: I've had a go at writing this, and bits of it turn out surprisingly easy. Code is available on github. Unfortunately, the best I can do so far is:
val result = where ( f1(1) * f2(2), {
def f1(x : Int) = x + 1
def f2(x : Int) = x + 2
})
The problem is that Scala's infix operators are just method calls, and so I'd need to have something constructed on the expression (f1(1) * f2(2)) in order to invoke them. But that's the very expression which won't type properly before macro resolution, so I'm not quite sure what to do. Time for a new question, methinks!
Found the following snippet on the Closure page on wikipedia
//# Return a list of all books with at least 'threshold' copies sold.
def bestSellingBooks(threshold: Int) = bookList.filter(book => book.sales >= threshold)
//# or
def bestSellingBooks(threshold: Int) = bookList.filter(_.sales >= threshold)
Correct me if I'm wrong, but this isn't a closure? It is a function literal, an anynomous function, a lambda function, but not a closure?
Well... if you want to be technical, this is a function literal which is translated at runtime into a closure, closing the open terms (binding them to a val/var in the scope of the function literal). Also, in the context of this function literal (_.sales >= threshold), threshold is a free variable, as the function literal itself doesn't give it any meaning. By itself, _.sales >= threshold is an open term At runtime, it is bound to the local variable of the function, each time the function is called.
Take this function for example, generating closures:
def makeIncrementer(inc: Int): (Int => Int) = (x: Int) => x + inc
At runtime, the following code produces 3 closures. It's also interesting to note that b and c are not the same closure (b == c gives false).
val a = makeIncrementer(10)
val b = makeIncrementer(20)
val c = makeIncrementer(20)
I still think the example given on wikipedia is a good one, albeit not quite covering the whole story. It's quite hard giving an example of actual closures by the strictest definition without actually a memory dump of a program running. It's the same with the class-object relation. You usually give an example of an object by defining a class Foo { ... and then instantiating it with val f = new Foo, saying that f is the object.
-- Flaviu Cipcigan
Notes:
Reference: Programming in Scala, Martin Odersky, Lex Spoon, Bill Venners
Code compiled with Scala version 2.7.5.final running on Java 1.6.0_14.
I'm not entirely sure, but I think you're right. Doesn't a closure require state (I guess free variables...)?
Or maybe the bookList is the free variable?
As far as I understand, this is a closure that contains a formal parameter, threshold and context variable, bookList, from the enclosing scope. So the return value(List[Any]) of the function may change while applying the filter predicate function. It is varying based on the elements of List(bookList) variable from the context.