[Haskell-cafe] Safe Haskell at the export symbol granularity?
dave.terei at gmail.com
Sat Jun 2 02:28:36 CEST 2012
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
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
- 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
- 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
I wrote some example code and a note about this stuff:
On 18 May 2012 06:58, Gábor Lehel <illissius at 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 at gmail.com> wrote:
>> Good point, Antoine!
>> I think that does the trick.
>> On Thu, May 17, 2012 at 10:48 AM, Antoine Latter <aslatter at gmail.com> wrote:
>>> On Thu, May 17, 2012 at 8:50 AM, Ryan Newton <rrnewton at 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.
>> Libraries mailing list
>> Libraries at haskell.org
> Work is punishment for failing to procrastinate effectively.
More information about the Haskell-Cafe