Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

The Archive Base

The Archive Base Logo The Archive Base Logo

The Archive Base Navigation

  • Home
  • SEARCH
  • About Us
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • Add group
  • Groups page
  • Feed
  • User Profile
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Buy Points
  • Users
  • Help
  • Buy Theme
  • SEARCH
Home/ Questions/Q 6530177
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: May 25, 20262026-05-25T09:43:27+00:00 2026-05-25T09:43:27+00:00

I’m working on some code that interfaces to a database schema that models a

  • 0

I’m working on some code that interfaces to a database schema that models a persistent graph. Before I go into the details of my specific question, I thought it might help to provide some motivation. My schema is around books, people and author roles. A book has many author roles, where each role has a person. However, instead of allowing direct UPDATE queries on book objects, you must create a new book, and make modifications to the new version.

Now, back to Haskell land. I am currently working with a few type classes, but importantly I have HasRoles and Entity:

class HasRoles a where
    -- Get all roles for a specific 'a'
    getRoles :: a -> IO [Role]

class Entity a where
    -- Update an entity with a new entity. Return the new entity.
    update :: a -> a -> IO a

Here comes my problem. When you are updating a book, you need to create a new book version but you also need to copy over the previous books roles (otherwise you lose data). The simplest way to do this is:

instance Entity Book where
    update orig newV = insertVersion V >>= copyBookRoles orig

This is fine, but there’s something that bugs me, and that’s the lack of any guarantee of the invariant that if something is an Entity and HasRoles, then inserting a new version will copy over the existing roles. I have thought of 2 options:

Use More Types

One ‘solution’ is to introduce the RequiresMoreWork a b. Going from the above, insertVersion now returns a HasRoles w => RequiresMoreWork w Book. update wants a Book, so to get out of the RequiresMoreWork value, we could call workComplete :: RequiresMoreWork () Book -> Book .

The real problem with this though, is that the most important piece of the puzzle is the type signature of insertVersion. If this doesn’t match the invariants (for example, it made no mention of needing HasRoles) then it all falls apart again, and we’re back to violating an invariant.

Prove it with QuickCheck

Moves the problem out of compile time, but at least we’re still asserting the invariant. In this case, the invariant is something like: for all entities that are also instances of HasRoles, inserting a new version of an existing value should have the same roles.


I’m a bit stumped on this. In Lisp I’d use method modifiers, in Perl I’d use roles, but is there anything I can use in Haskell?

  • 1 1 Answer
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

1 Answer

  • Voted
  • Oldest
  • Recent
  • Random
  1. Editorial Team
    Editorial Team
    2026-05-25T09:43:27+00:00Added an answer on May 25, 2026 at 9:43 am

    I’m of two minds as to how I should respond to this:

    This is fine, but there’s something that bugs me, and that’s the lack
    of any guarantee of the invariant that if something is an Entity and
    HasRoles, then inserting a new version will copy over the existing
    roles.

    One the one hand, if something is an Entity, it doesn’t matter if it HasRoles or not. You simply provide the update code, and it should be correct for that specific type.

    On the other, this does mean that you’ll be reproducing the copyRoles boilerplate for each of your types and you certainly could forget to include it, so it’s a legitimate problem.

    When you require dynamic dispatch of this nature, one option is to use a GADT to scope over the class context:

    class Persisted a where
        update :: a -> a -> IO a
    
    data Entity a where
        EntityWithRoles :: (Persisted a, HasRoles a) => a -> Entity a
        EntityNoRoles   :: (Persisted a) => a -> Entity a
    
    instance Persisted (Entity a) where
        insert (EntityWithRoles orig) (EntityWithRoles newE) = do
          newRoled <- copyRoles orig newE
          EntityWithRoles <$> update orig newRoled
        insert (EntityNoRoles orig) (EntityNoRoles newE) = do
          EntityNoRoles <$> update orig newE
    

    However, given the framework you’ve described, rather than having an update class method, you could have a save method, with update being a normal function

    class Persisted a where
        save :: a -> IO ()
    
    -- data Entity as above
    
    update :: Entity a -> (a -> a) -> IO (Entity a)
    update (EntityNoRoles orig) f = let newE = f orig in save newE >> return (EntityNoRoles newE)
    update (EntityWithRoles orig) f = do
      newRoled <- copyRoles orig (f orig)
      save newRoled
      return (EntityWithRoles newRoled)
    

    I would expect some variation of this to be much simpler to work with.

    A major difference between type classes and OOP classes is that type class methods don’t provide any means of code re-use. In order to re-use code, you need to pull the commonalities out of type class methods and into functions, as I did with update in the second example. An alternative, which I used in the first example, is to convert everything into some common type (Entity) and then only work with that type. I expect the second example, with a standalone update function, would be simpler in the long run.

    There is another option that may be worth exploring. You could make HasRoles a superclass of Entity and require that all your types have HasRoles instances with dummy functions (e.g. getRoles _ = return []). If most of your entities would have roles anyway, this is actually pretty convenient to work with and it’s completely safe, although somewhat inelegant.

    • 0
    • Reply
    • Share
      Share
      • Share on Facebook
      • Share on Twitter
      • Share on LinkedIn
      • Share on WhatsApp
      • Report

Sidebar

Related Questions

link Im having trouble converting the html entites into html characters, (&# 8217;) i
I have a French site that I want to parse, but am running into
I'm parsing an RSS feed that has an &#8217; in it. SimpleXML turns this
I ran into a problem. Wrote the following code snippet: teksti = teksti.Trim() teksti
That's pretty much it. I'm using Nokogiri to scrape a web page what has
I have just tried to save a simple *.rtf file with some websites and
For some reason, after submitting a string like this Jack’s Spindle from a text
this is what i have right now Drawing an RSS feed into the php,
I've got a string that has curly quotes in it. I'd like to replace
I am currently running into a problem where an element is coming back from

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help
  • SEARCH

Footer

© 2021 The Archive Base. All Rights Reserved
With Love by The Archive Base

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.