I would represent the data structure in a pure way, and restrict the
IO monad to the operations that actually do IO.
If you need some kind of mutable graph, I suggest representing that
graph as a map (Data.Map) from node names to neighbors.
The "mutation" is then just updating the map.  An extra benefit from
this is that you get really simple undo in your editor.

  -- Lennart

On Thu, Sep 4, 2008 at 8:53 AM, minh thu <[EMAIL PROTECTED]> wrote:
> 2008/9/4 Timothy Goddard <[EMAIL PROTECTED]>:
>> It looks like this code isn't really in fitting with normal Haskell idioms.
>
> I guess you mean by Haskell idiom : "pure". But Haskell allows you to
> do IO, etc.
>
>> 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.
>
> Thanks for the exemple, but I'm aware of monads (even if I can't still
> use them easily when
> many of them are mixed).
> Here my problem is more about interactively editable data structure
> (at least from the
> point of view of the user). I would be very happy to do it with pure 
> functions.
>
>> 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.
>
> I'm looking at the FGL package, it seems very intersting. I don't
> think immutable data
> structures imply poor perfromance, but I think designing the examples you give
> is quite complicated and done by really experienced Haskell programmers.
> Please, don't answer to my problem (even if I haven't really explain
> it) by exposing
> state-of-the-art Haskell goodness.
>
>> 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.
>
> Overall, I agree I have to look for a more pure approach. Although, I
> think something like
> FGL required a lot of work. But raising, say, uvector, in face of my
> use of IORef seems a bit
> quick.
>
>> Good luck,
>
> Thank you,
> Thu
>
>>
>> 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@haskell.org
>>> http://www.haskell.org/mailman/listinfo/haskell-cafe
>> _______________________________________________
>> Haskell-Cafe mailing list
>> Haskell-Cafe@haskell.org
>> http://www.haskell.org/mailman/listinfo/haskell-cafe
>>
> _______________________________________________
> Haskell-Cafe mailing list
> Haskell-Cafe@haskell.org
> http://www.haskell.org/mailman/listinfo/haskell-cafe
>
_______________________________________________
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe

Reply via email to