[Haskell-cafe] Strong duck typing / structural subtyping / type class aliases / ??? in Haskell
Alp Mestan wrote: Indeed, OCaml has stuctural polymorphism, it's a wonderful feature. *# let f myobj = myobj#foo Hi !;; val f : foo : string - 'a; .. - 'a = fun* And Haskell has that too: -- This is how we define labels. data Field1 deriving Typeable; field1 = proxy::Proxy Field1 -- This is how record selection looks like. foo f = f # field1 The inferred type of foo is *OCamlTutorial :t foo foo :: (HasField (Proxy Field1) r v) = r - v It doesn't seem too different from the OCaml's type; the type variable r acts as a row type. The quoted example is the first from many others described in http://darcs.haskell.org/OOHaskell/OCamlTutorial.hs The file quotes at length OCaml's Object tutorial and then demonstrates how the OCaml code can be written in Haskell. When it comes to objects, structural subtyping, width and depth subtyping, etc., Haskell does not seem to miss match compared to OCaml. In contrast, Haskell has a few advantages when it comes to coercions (one does not have to specify the type to coerce to, as Haskell can figure that out). The other files in that directory give many more example of encoding C++, Eiffel, OCaml patterns. ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
[Haskell-cafe] Strong duck typing / structural subtyping / type class aliases / ??? in Haskell
Haskell's records are a bit annoying, and type-classes often group together too many methods, which means you make early decisions about future unknown requirements, and IMO you always get it wrong :-) After having read an email in the cafe about the Noop language Self language, I realized that what I really would like to have is strong duck typing on records (or is it called structural subtyping? or prototype-based-objects? or something like that) For example (silly example full of inaccuracies, but you get the picture): class HasPosition a where position :: a - Point withPosition :: Point - a - a class HasVelocity a where velocity :: a - Vector withVelocity :: Vector - a - a which we really should write as field HasPosition :: Point field HasVelocity :: Vector And then record IsKinetic :: HasPosition HasVelocity suppose we write a function like kineticEulerStep dt k = withPosition (position k .+^ dt *^ velocity k) k kineticEulerStep will work on any type a that HasPosition and HasVelocity, and would get inferred signature kineticEulerStep :: IsKinetic a = Float - a - a which is identical to kineticEulerStep :: (HasPosition a, HasVelocity a) = Float - a - a So basically kineticEulerStep accepts anything that HasPosition and HasVelocity, whatever it is. So if it walks like a duck and ..., then it is a duck, but statically known... We could also do field HasForce :: Vector field HasMass :: Float record IsDynamic :: IsKinetic HasForce HasMass acceleration d = force d ^/ mass d withAcceleration a d = withForce (a ^* mass d) d dynamicEulerStep dt d = withVelocity (velocity d ^+^ dt *^ acceleration d) Of course you would also need type families to be really correct since Vector, Point, etc should also be parametrized. And really kineticEulerStep might also work on something that HasVelocity and HasAcceleration (since the code in dynamicEulerStep is almost the same as kineticEulerStep), so better abstraction might be needed. I'm not sure what kind of overhead a system like this would have in Haskell, since I suspect the many dictionaries are often not optimized away. I think for Haskell prime, something like this was suggestedhttp://repetae.net/recent/out/classalias.html, but is was rejected? Languages like OCaml and haXe http://haxe.org/manual/2_types also provide a similar feature? I would like to collect ways of doing this in Haskell, without boilerplate, and preferably without runtime overhead. I remember reading OOHaskell a while time ago, and while I didn't understand a lot of it, I recall it also was doing a similar thing, but since the compiler lacks native support, the error messages you get most likely make it impossible to figure out what is going wrong. I think Grapefruit's Records, HList, Data.Accessor, etc.. might also work. Any guidelines and comments regarding strong duck typing/structural subtyping are very welcome, since the lack of this is the only reason why I would prefer a dynamic language over a static one. Thanks a lot, Peter Verswyvelen ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] Strong duck typing / structural subtyping / type class aliases / ??? in Haskell
Short answer: There is no good way of doing what you want. This is actually one of my biggest annoyances with haskell (right up there with disallowing infinite types). They are many techniques that work better or worse depending on the application, but non are very satisfactory IMO. Your typeclass solution(or some variant of) is pretty much your best option. If you're careful about how you define your datatype and classes you can avoid the type families and such, but the whole point is to not have to be careful. If your types are fixed (which is usually true as long as you're not using existentials) you might be able to get away with using -XDisambiguateFieldRecords If you want anything better you're probably going to have to use some form of preprocessor (like OHaskell). Supposedly OCaml has an OO feature that does this but I haven't tried it out. I would suspect that the reason why haskell doesn't provide duck typeing on record fields is that analisys for optimizations is much more complicated (as it currently stands, records are nothing but sugar on top of algeraic datatypes). You can end up with all sorts of weird things with duck typeing on record fields, like unnamed datatypes. For example: (using class constraint style to inidicate a record field restriction for lack of a better syntax) setPosition :: (position a) =Vector - a - a setPosition v x = x { position = v } translate :: (position a) =Vector - a - a translate v x = x { position = v + (position x) } getPosition :: (position a) = a - Vector getPosition x = position x result :: Vector result = getPosition $ translate someVector $ setPosition someOtherVector The type variable 'a' in these functions is never fixed to a specific type, and it actually doesn't need to be. The compiler would just have to invent a suitable one (a type with only the field 'position' of type Vector). Maybe someday haskell will finially implement good, clean, duck typeable, record functionality. I will be waiting... - Job On Fri, Sep 25, 2009 at 9:54 AM, Peter Verswyvelen bugf...@gmail.comwrote: Haskell's records are a bit annoying, and type-classes often group together too many methods, which means you make early decisions about future unknown requirements, and IMO you always get it wrong :-) After having read an email in the cafe about the Noop language Self language, I realized that what I really would like to have is strong duck typing on records (or is it called structural subtyping? or prototype-based-objects? or something like that) For example (silly example full of inaccuracies, but you get the picture): class HasPosition a where position :: a - Point withPosition :: Point - a - a class HasVelocity a where velocity :: a - Vector withVelocity :: Vector - a - a which we really should write as field HasPosition :: Point field HasVelocity :: Vector And then record IsKinetic :: HasPosition HasVelocity suppose we write a function like kineticEulerStep dt k = withPosition (position k .+^ dt *^ velocity k) k kineticEulerStep will work on any type a that HasPosition and HasVelocity, and would get inferred signature kineticEulerStep :: IsKinetic a = Float - a - a which is identical to kineticEulerStep :: (HasPosition a, HasVelocity a) = Float - a - a So basically kineticEulerStep accepts anything that HasPosition and HasVelocity, whatever it is. So if it walks like a duck and ..., then it is a duck, but statically known... We could also do field HasForce :: Vector field HasMass :: Float record IsDynamic :: IsKinetic HasForce HasMass acceleration d = force d ^/ mass d withAcceleration a d = withForce (a ^* mass d) d dynamicEulerStep dt d = withVelocity (velocity d ^+^ dt *^ acceleration d) Of course you would also need type families to be really correct since Vector, Point, etc should also be parametrized. And really kineticEulerStep might also work on something that HasVelocity and HasAcceleration (since the code in dynamicEulerStep is almost the same as kineticEulerStep), so better abstraction might be needed. I'm not sure what kind of overhead a system like this would have in Haskell, since I suspect the many dictionaries are often not optimized away. I think for Haskell prime, something like this was suggestedhttp://repetae.net/recent/out/classalias.html, but is was rejected? Languages like OCaml and haXe http://haxe.org/manual/2_types also provide a similar feature? I would like to collect ways of doing this in Haskell, without boilerplate, and preferably without runtime overhead. I remember reading OOHaskell a while time ago, and while I didn't understand a lot of it, I recall it also was doing a similar thing, but since the compiler lacks native support, the error messages you get most likely make it impossible to figure out what is going wrong. I think Grapefruit's Records, HList, Data.Accessor, etc.. might also work. Any guidelines and comments regarding
Re: [Haskell-cafe] Strong duck typing / structural subtyping / type class aliases / ??? in Haskell
On Fri, Sep 25, 2009 at 8:14 PM, Job Vranish jvran...@gmail.com wrote: Supposedly OCaml has an OO feature that does this but I haven't tried it out. Indeed, OCaml has stuctural polymorphism, it's a wonderful feature. *# let f myobj = myobj#foo Hi !;; val f : foo : string - 'a; .. - 'a = fun* IIRC, there has been work on Template Haskell for structural polymorphism. -- Alp Mestan http://blog.mestan.fr/ http://alp.developpez.com/ ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] Strong duck typing / structural subtyping / type class aliases / ??? in Haskell
On Fri, 25 Sep 2009 23:25:21 +0200, you wrote: On Fri, Sep 25, 2009 at 8:14 PM, Job Vranish jvran...@gmail.com wrote: Supposedly OCaml has an OO feature that does this but I haven't tried it out. Indeed, OCaml has stuctural polymorphism, it's a wonderful feature. *# let f myobj = myobj#foo Hi !;; val f : foo : string - 'a; .. - 'a = fun* IIRC, there has been work on Template Haskell for structural polymorphism. Structural subtyping/polymorphism: Pros: - an object can be coerced to any compatible type, the types do not have to be specified ahead of time, that is at compile time. Cons: - may be overly permissive; some coercions might not make sense semantically. I wonder how Haskell will minimize the cons, since it is strongly typed. -- Regards, Casey ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] Strong duck typing / structural subtyping / type class aliases / ??? in Haskell
On Fri, 25 Sep 2009 23:25:21 +0200, you wrote: On Fri, Sep 25, 2009 at 8:14 PM, Job Vranish jvran...@gmail.com wrote: Supposedly OCaml has an OO feature that does this but I haven't tried it out. Indeed, OCaml has stuctural polymorphism, it's a wonderful feature. *# let f myobj = myobj#foo Hi !;; val f : foo : string - 'a; .. - 'a = fun* IIRC, there has been work on Template Haskell for structural polymorphism. Structural subtyping/polymorphism: Pros: - an object can be coerced to any compatible type, the types do not have to be specified ahead of time, that is at compile time. Cons: - may be overly permissive; some coercions might not make sense semantically. I wonder how Haskell will minimize the cons, since it is strongly typed. I forgot to add: that even if strong typing could be measured on sum numerical scale, I don't know whether Haskell has a higher measure/metric than OCaml, in the strong typing area. -- Regards, Casey ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] Strong duck typing / structural subtyping / type class aliases / ??? in Haskell
Peter Verswyvelen wrote: After having read an email in the cafe about the Noop language Self language, I realized that what I really would like to have is strong duck typing on records (or is it called structural subtyping? or prototype-based-objects? or something like that) The common name for (one form of) what you're seeking is row polymorphism: http://www.cs.cmu.edu/~neelk/rows.pdf This is implemented in OCaml but, like most OO features in functional languages, it is often ignored or forgotten about. As others've mentioned, there are some cases where row polymorphism is really nice, but it's not always semantically coherent. -- Live well, ~wren ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] Strong duck typing / structural subtyping / type class aliases / ??? in Haskell
On Fri, Sep 25, 2009 at 10:55 PM, Casey Hawthorne cas...@istar.ca wrote: On Fri, 25 Sep 2009 23:25:21 +0200, you wrote: On Fri, Sep 25, 2009 at 8:14 PM, Job Vranish jvran...@gmail.com wrote: Supposedly OCaml has an OO feature that does this but I haven't tried it out. Indeed, OCaml has stuctural polymorphism, it's a wonderful feature. *# let f myobj = myobj#foo Hi !;; val f : foo : string - 'a; .. - 'a = fun* IIRC, there has been work on Template Haskell for structural polymorphism. Structural subtyping/polymorphism: Pros: - an object can be coerced to any compatible type, the types do not have to be specified ahead of time, that is at compile time. Cons: - may be overly permissive; some coercions might not make sense semantically. I wonder how Haskell will minimize the cons, since it is strongly typed. I kind of think there's no real problem here. If you say that you can accept any record with a given set of fields, then you have to make sure you make no other assumptions. This is, in principle, no different from passing a speed Double to a function that expects a mass Double (e.g. it may produce garbage for negative values). In both cases a function that requires extra invariants can enforce it by using a newtype that's constructed and manipulated in a way which preserves the extra semantic rules. -- Sebastian Sylvan ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe