What you want to do is make your Vector an instance of the Num(eric) type class. For instance: instance Num Vector where (+) v1 v2 = zipWith (+) v1 v2 (-) v1 v2 = zipWith (-) v1 v2 negate v1 = map negate v1 abs v1 = map abs v1 (*) v1 v2 = ... fromInteger i = ... signum v1 = ... I've left the last three blank because it's unclear what should go there. Since (*) has type Vector->Vector->Vector (in this instance), you can't use dot product or something like that. signum :: Vector->Vector could be written and just return [-1], [0] or [1], I suppose. fromInteger :: Integer->Vector is a little harder. Perhaps just 'fromInteger i = [fromInteger i]' would be acceptable. Or you could leave these undefined. -- Hal Daume III | hdaume@isi.edu "Arrest this man, he talks in maths." | www.isi.edu/~hdaume
-----Original Message----- From: haskell-admin@haskell.org [mailto:haskell-admin@haskell.org] On Behalf Of Liu Junfeng Sent: Wednesday, July 09, 2003 7:25 AM To: haskell@haskell.org Subject: How overload operator in Haskell?
I've learned haskell months, but I still can't understand the type system very well. I can only write: ----------------------------------- type Vector = [Double] vadd,vsub :: Vector->Vector->Vector v1 `vadd` v2 = zipWith (+) v1 v2 v1 `vsub` v2 = zipWith (-) v1 v2 svmul :: Double->Vector->Vector s `svmul` v = map (s*) v ------------------------------------ Tough it works, it is not convenient to use. How to create a Vector type and overload mathematical operators? Thanks for your help.
Liu Junfeng liujf@softhome.net
_______________________________________________ Haskell mailing list Haskell@haskell.org http://www.haskell.org/mailman/listinfo/haskell
Hal Daume answers a question on how to define nice, infix ops acting on vectors:
What you want to do is make your Vector an instance of the Num(eric) type class. For instance:
instance Num Vector where (+) v1 v2 = zipWith (+) v1 v2 (-) v1 v2 = zipWith (-) v1 v2 negate v1 = map negate v1 abs v1 = map abs v1 (*) v1 v2 = ... fromInteger i = ... signum v1 = ...
I've left the last three blank because it's unclear what should go there. Since (*) has type Vector->Vector->Vector (in this instance), you can't use dot product or something like that.
signum :: Vector->Vector could be written and just return [-1], [0] or [1], I suppose.
fromInteger :: Integer->Vector is a little harder. Perhaps just 'fromInteger i = [fromInteger i]' would be acceptable. Or you could leave these undefined.
-- Hal Daume III | hdaume@isi.edu "Arrest this man, he talks in maths." | www.isi.edu/~hdaume
While this is a possible solution, I would shout loudly: "Arrest this man, he is disrespectful wrt math!". Actually, this shows once more that the Num class and its relatives is a horror... Signum in this context has no sense. The multiplication might be the cross product, but its anti-commutativity shows plainly that this is not a 'standard' multiplication. 'fromInteger' has even less sense than signum... I am particularly horrified by "abs v = map abs v", and I am sure all of you see why. I think that a more sane solution would be the definition of a particular class with operations porting names like <+>, or ^+^, or whatever similar to standard ones, but different. Jerzy Karczmarczuk
G'day all. On Wed, Jul 09, 2003 at 05:25:20PM +0200, Jerzy Karczmarczuk wrote:
While this is a possible solution, I would shout loudly: "Arrest this man, he is disrespectful wrt math!". Actually, this shows once more that the Num class and its relatives is a horror...
Yup. I recently discovered, to my delight, that single-method typeclasses with no superclasses are represented as a single unboxed function in GHC (i.e. the type dictionary is "newtype" rather than "data"). This suggests that wrapping each "standard" mathemtaical function/operator in its own typeclass would have literally no run-time performance penalty: class Plus a b c | a b -> c where (+) :: a -> b -> c class Mult a b c | a b -> c where (*) :: a -> b -> c {- etc -} class (Eq a, Show a, Plus a a a, Mult a a a, {- etc -} ) => Num a Apart from the possibility of naming these typeclasses better, this reorganisation gets my vote for Haskell 2.
Signum in this context has no sense.
An even weirder example is that of the two real number libraries in haskell-libs. Computable reals are definitely numbers, but they're not even members of Eq. Cheers, Andrew Bromage
On Thu, 10 Jul 2003 10:58:51 +1000, Andrew J Bromage <ajb@spamcop.net> wrote:
This suggests that wrapping each "standard" mathemtaical function/operator in its own typeclass would have literally no run-time performance penalty:
class Plus a b c | a b -> c where (+) :: a -> b -> c
class Mult a b c | a b -> c where (*) :: a -> b -> c
{- etc -}
class (Eq a, Show a, Plus a a a, Mult a a a, {- etc -} ) => Num a
Apart from the possibility of naming these typeclasses better, this reorganisation gets my vote for Haskell 2.
Given the current way the system works, this imposes a syntactic penalty on people wishing to declare an instance of Num. If some nice change can be made to avoid this, e.g. by allowing people to declare instances of several classes in the same instance declaration and automatically inferring the names of the relevant base classes, then this would be a very good thing. Ganesh
In article <20030710005851.GA1068@smtp.alicorna.com>, Andrew J Bromage <ajb@spamcop.net> wrote:
This suggests that wrapping each "standard" mathemtaical function/operator in its own typeclass would have literally no run-time performance penalty:
class Plus a b c | a b -> c where (+) :: a -> b -> c
class Mult a b c | a b -> c where (*) :: a -> b -> c
As written, this is _not_ a good idea. Trust me, you end up having to put type annotations everywhere. Even (3 + 4 :: Integer) is ambiguous, you have to write (3 :: Integer) + (4 :: Integer). In HBase, I do this: class Additive a b ab | a b -> ab where add :: a -> b -> ab; infixl 6 +; (+) :: (Additive a a a) => a -> a -> a; b + a = add a b; etc. The arguments are swapped because I read "subtract 1 a" and "a - 1" both as "subtract 1 from a", etc. Perhaps one could get away with this: (+) :: (Additive a b a) => a -> b -> a; -- Ashley Yakeley, Seattle WA
G'day all. On Thu, Jul 10, 2003 at 11:16:56PM -0700, Ashley Yakeley wrote:
As written, this is _not_ a good idea. Trust me, you end up having to put type annotations everywhere. Even (3 + 4 :: Integer) is ambiguous, you have to write (3 :: Integer) + (4 :: Integer).
But that's what default() is for! Cheers, Andrew Bromage
On Fri, Jul 11, 2003 at 05:38:18PM +1000, Andrew J Bromage wrote:
G'day all.
On Thu, Jul 10, 2003 at 11:16:56PM -0700, Ashley Yakeley wrote:
As written, this is _not_ a good idea. Trust me, you end up having to put type annotations everywhere. Even (3 + 4 :: Integer) is ambiguous, you have to write (3 :: Integer) + (4 :: Integer).
But that's what default() is for!
Don't be silly: the default mechanism is a very special case that is not good for general use. It would make all user-defined numeric types essentially unuseable, for one thing. (Unless you have a proposal to make the default mechanism more general?) Peace, Dylan
On 2003-07-12 at 20:20+1000 Andrew J Bromage wrote:
G'day all.
On Fri, Jul 11, 2003 at 04:28:19PM -0400, Dylan Thurston wrote:
Don't be silly [...]
Never!
Or only sometimes. I'm surprised that no-one has yet answered the question "How overload operator in Haskell?" with "Overload operator in Haskell fine". (cf Cary Grant) -- Jón Fairbairn Jon.Fairbairn@cl.cam.ac.uk 31 Chalmers Road jf@cl.cam.ac.uk Cambridge CB1 3SZ +44 1223 570179 (after 14:00 only, please!)
Andrew J Bromage <ajb@spamcop.net> writes:
class Plus a b c | a b -> c where (+) :: a -> b -> c
class Mult a b c | a b -> c where (*) :: a -> b -> c
This kind of approach was discussed a while ago, and has a bunch of things to recommend it. Is the functional dependency sufficient to avoid any ambiguity?
class (Eq a, Show a, Plus a a a, Mult a a a, {- etc -} ) => Num a
Apart from the possibility of naming these typeclasses better, this reorganisation gets my vote for Haskell 2.
Add the ability to do instance Num Foo where a + b = ... a - b = ... a * b = ... i.e when instantiating a derived class (if one can call it that), allow implicit instantiation of base classes. One thing to look out for, is a hierarchy of esoterically named classes, and consequentially, error messages incomprehensible to people unfamiliar with the details of the hierarchy. -kzm -- If I haven't seen further, it is by standing in the footprints of giants
On Wednesday, 2003-07-09, 17:11, CEST, Hal Daume wrote:
What you want to do is make your Vector an instance of the Num(eric) type class.
It would be better to define one's own operators instead of using + and - because Vector has no meaningful instance of Num (as Jerzy Karczmarczuk already pointed out). But maybe it's overkill to define a new class if you don't want the same operators for other types.
For instance:
instance Num Vector where (+) v1 v2 = zipWith (+) v1 v2 (-) v1 v2 = zipWith (-) v1 v2
You can also use the nice infix syntax in definitions (as you already did with your `vadd` and `vsub`): v1 + v2 = zipWith (+) v1 v2 v1 - v2 = zipWith (-) v1 v2
[...]
Wolfgang
Hal Daume wrote:
What you want to do is make your Vector an instance of the Num(eric) type class. For instance:
instance Num Vector where
Except that class instances have to be algebraic datatypes ("data") or renamed datatypes ("newtype"), but not type synonyms ("type"). -- Glynn Clements <glynn.clements@virgin.net>
In article <16140.55249.147965.603167@cerise.nosuchdomain.co.uk>, Glynn Clements <glynn.clements@virgin.net> wrote:
instance Num Vector where
Except that class instances have to be algebraic datatypes ("data") or renamed datatypes ("newtype"), but not type synonyms ("type").
That's not true, is it? I mean as long as there isn't already some overlapping instance, I think it's quite OK. -- Ashley Yakeley, Seattle WA
fre 2003-07-11 klockan 08.07 skrev Ashley Yakeley:
In article <16140.55249.147965.603167@cerise.nosuchdomain.co.uk>, Glynn Clements <glynn.clements@virgin.net> wrote:
instance Num Vector where
Except that class instances have to be algebraic datatypes ("data") or renamed datatypes ("newtype"), but not type synonyms ("type").
That's not true, is it? I mean as long as there isn't already some overlapping instance, I think it's quite OK.
Well, there's the "The instance type must be of form (T a b c) where T is not a synonym, and a,b,c are distinct type variables" restriction (ghc), or as hugs put it: "Cannot use type synonym in instance head" You get around it with hugs -98 or ghc -fglasgow-exts. Dunno about nhc98. /Martin NB: I just used class Foo ; instance Foo String to produce these error messages... -- Martin Sjögren martin@strakt.com Phone: +46 (0)31 7490880 Cell: +46 (0)739 169191 GPG key: http://www.strakt.com/~martin/gpg.html
At 23:07 10/07/03 -0700, Ashley Yakeley wrote:
In article <16140.55249.147965.603167@cerise.nosuchdomain.co.uk>, Glynn Clements <glynn.clements@virgin.net> wrote:
instance Num Vector where
Except that class instances have to be algebraic datatypes ("data") or renamed datatypes ("newtype"), but not type synonyms ("type").
That's not true, is it? I mean as long as there isn't already some overlapping instance, I think it's quite OK.
It's true of strict Haskell 98 (see report, section 4.3.2), but I think the condition is relaxed in GHC. #g ------------------- Graham Klyne <GK@NineByNine.org> PGP: 0FAA 69FF C083 000B A2E9 A131 01B9 1C7A DBCA CB5E
participants (12)
-
Andrew J Bromage -
Ashley Yakeley -
Dylan Thurston -
Ganesh Sittampalam -
Glynn Clements -
Graham Klyne -
Hal Daume -
Jerzy Karczmarczuk -
Jon Fairbairn -
ketil@ii.uib.no -
Martin Sjögren -
Wolfgang Jeltsch