So this is a good question, sorry for the late reply. It's tricky as the way typeclasses are imported and exported in Haskell is confusing. Basically, instances are hard to control access to as they aren't part of import or export statements. Importing a module that defines an instances gives you those instances. This works transitively so you have access to all instances defined below you in the dependency graph. Controlling access to a typeclass function is easy though, it works just like a normal function. So in your example, the Safe module wouldn't necessarily become unsafe but there is some unsatisfactory trickiness. - untrusted code still couldn't access the type class as the functions for it aren't exported. - the derived functions may or may not be safe anymore depending on polymorphism: - If the derived functions don't have any polymorphism that would allow consumers of the functions to choose what underlying typeclass is used, then the module is still safe. - If they do, then yes untrusted code could choose what types to use to cause the unsafe instance to be used, thus making the derived functions unsafe. (This assumes the untrusted code has access to the unsafe instance but as I said, this is hard to reason about since instances are somewhat global). there are solutions to this problem but its a tricky situation with the solutions really being to be careful... I don't know how we could do better. Tracking safety at the symbol level doesn't seem like it would change this situation. Basically you want closed type classes or a way to control what instances can be used (maybe by simply making instances part of import/export lists) both of which are big changes to Haskell. I wrote some example code and a note about this stuff: https://github.com/dterei/SafeHaskellExamples/tree/master/typeclasses Cheers, David On 18 May 2012 06:58, Gábor Lehel <illissius@gmail.com> wrote:
I have a related-seeming question:
Say I have a type class with methods, and some functions implemented on top of it. The class methods are inherently unsafe. Instances of the class are supposed to satisfy some conditions, and if those conditions are met, the functions built on top are safe.
So say I put the class in an Unsafe module, and re-export the class without its methods along with the derived functions in a Safe module. For anything unsafe to happen, the Unsafe module has to be imported somewhere. But if someone imports it and implements a bad instance, the Safe module *also* becomes potentially unsafe! What's the recommended practice here?
(I can't really tell if this is the same question as originally posed by Ryan, but I think it's not.)
On Thu, May 17, 2012 at 4:53 PM, Ryan Newton <rrnewton@gmail.com> wrote:
Good point, Antoine!
I think that does the trick.
On Thu, May 17, 2012 at 10:48 AM, Antoine Latter <aslatter@gmail.com> wrote:
On Thu, May 17, 2012 at 8:50 AM, Ryan Newton <rrnewton@gmail.com> wrote:
Thanks David.
I'm glad to see it was discussed in the wiki. (Btw, my 2 cents is that I like the comment pragmas more than new keywords.)
The issue that I think doesn't make it into the wiki is of splitting, not modules, but type-classes. That's where I think it becomes a more serious issue.
Do you think a symbol-level Safe Haskell would be able to distinguish one method of a type class as unsafe, while the others are safe?
You can still do this at the module level, with the down-side of potentially not being able to implement a class with the safe version:
module Unsafe where
class MyClass a where safeOp :: a -> Int -> IO () unsafeOp :: a -> Int -> IO ()
instance MyClass A where ...
module Safe (MyClass(safeOp)) where
import Unsafe
I think this works.
Antoine
_______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries
-- Work is punishment for failing to procrastinate effectively.