[Haskell-cafe] Is it usual to read a Maybe (IORef a) ?

Timothy Goddard tim at goddard.net.nz
Thu Sep 4 02:33:22 EDT 2008


It looks like this code isn't really in fitting with normal Haskell idioms. 
Emulating C in Haskell will only give you a harder way of writing C. Don't 
think about emulating a potentially null pointer with Maybe (IORef a) and 
passing this to a function to read content unless you also want to implement 
the function "segfault :: IO ()".

You really need to ask yourself whether it makes sense to read a NULL / 
Nothing field. In C this would cause a segfault. The idea in Haskell is that 
you don't allow invalid values to be passed in to a function at all. Each 
function should be pure and accept only sensible inputs, allowing you to 
analyse what each function does in isolation from the rest of the program.

In Haskell, functions should use the type system to only accept arguments 
which make sense. The caller should handle the possibility that a function it 
calls returns nothing, not expect every other callee to do so. The Maybe 
monad helps with this for many cases:

lookupEmployee :: Integer -> Maybe Employee
lookupPassportNo :: Employee -> PassportNo
lookupMarriageCertificate :: PassportNo -> Maybe MarriageCert
getPassportNumbers :: MarriageCert -> (PassportNo, PassportNo)
getNameFromPassport :: PassportNo -> Maybe String

lookupSpouse :: Integer -> Maybe String
lookupSpouse employee_no = do
	employee <- lookupEmployee employee_no
	let passport = lookupPassportNo employee
	cert <- lookupMarriageCertificate
	let (p1, p2) = getPassportNumbers cert
	let partner = if p1 == passport then p2 else p1
	getNameFromPassport partner

In this example, if any lookup which can fail does, the result is Nothing. 
Each lookup function can assume that a valid argument is present, though some 
types of lookup may still give no result. The caller chooses how to account 
for this inability to find a match, in this case by itself having no result.

The thing I'm more concerned about here is the use of IORefs inside data 
structures at all. A data structure containing IORefs is mutable and can only 
be manipulated in the IO monad, which defeats the point of Haskell. There is 
a use case for using mutable structures for some resource-intensive 
operations, but even then it's often trading short-term speed for long term 
difficulties. If you think immutable structures imply poor performance, take 
a look at projects such as uvector and Data Parallel Haskell - immutable data 
structures which beat the hell out traditional, C-like techniques.

If you must use IORefs, consider only using them to hold the whole structure, 
which is modified by normal, pure functions. If you don't think you can make 
do with this, you're probably still thinking about the program in an 
imperative manner. You will probably be better off either rethinking how 
you're doing things or, if you cannot translate the concepts to a functional 
form, using an imperative language.

Good luck,

Tim

On Wed, 03 Sep 2008 22:09:38 minh thu wrote:
> Hi,
>
> I'd like to write a data structure to be used inside the IO monad.
> The structure has some handles of type Maybe (IORef a),
> i.e. IORef are pointers and the Maybe is like null pointers.
>
> So I came up with the following functions :
>
> readHandle :: Maybe (IORef a) -> IO (Maybe a)
> readField :: (a -> b) -> Maybe (IORef a) -> IO (Maybe b)
>
> readHandle Nothing  = do
>   return Nothing
> readHandle (Just r) = do
>   v <- readIORef r
>   return $ Just v
>
> readField f h = do
>   m <- readHandle h
>   return $ fmap f m
>
> Is it something usual ?
> Are there any related functions in the standard libraries ?
>
> Thanks,
> Thu
> _______________________________________________
> Haskell-Cafe mailing list
> Haskell-Cafe at haskell.org
> http://www.haskell.org/mailman/listinfo/haskell-cafe


More information about the Haskell-Cafe mailing list