[GHC] #13028: Compile-time validation of literals in IsString instances

GHC ghc-devs at haskell.org
Thu Dec 22 08:45:21 UTC 2016


#13028: Compile-time validation of literals in IsString instances
-------------------------------------+-------------------------------------
           Reporter:  jml            |             Owner:
               Type:  feature        |            Status:  new
  request                            |
           Priority:  normal         |         Milestone:
          Component:  Compiler       |           Version:  8.0.1
           Keywords:                 |  Operating System:  Unknown/Multiple
       Architecture:                 |   Type of failure:  None/Unknown
  Unknown/Multiple                   |
          Test Case:                 |        Blocked By:
           Blocking:                 |   Related Tickets:
Differential Rev(s):                 |         Wiki Page:
-------------------------------------+-------------------------------------
 I would like to be able to make `IsString` instances using the
 `OverloadedStrings` extension such that my instance rejects some literals
 as being invalid and such that that rejection happens at compile time, so
 that programming mistakes don't make it into the code I give to my users.

 I have a couple of use cases where I have a `Name` type that only admits
 certain strings. e.g.

 {{{#!hs
 module Name (Name(getName), makeName) where

 import Data.Text (Text)
 import qualified Data.Text as Text

 -- | A guaranteed non-empty name.
 newtype Name = Name { getName :: Text } deriving (Eq, Show, Ord)

 makeName :: Text -> Maybe Name
 makeName name
   | Text.null name = Nothing
   | otherwise = Just name
 }}}

 In a real use case, I'd check for valid characters, not starting with a
 digit, that sort of thing.

 The idea is that we don't export the `Name` constructor, which means
 anyone using a `Name` value can trust that it has certain properties (in
 this case, non-empty).

 My problem is that I'd like to use literal names in many places. e.g.

 {{{#!hs
 programName :: Name
 programName = fromJust $ makeName "the-great-and-powerful-turtle"
 }}}

 Because I do this a lot, I've defined an `unsafeMakeName` helper that does
 pretty much the same thing:

 {{{#!hs
 unsafeMakeName :: Text -> Name
 unsafeMakeName name = fromMaybe (error $ "Invalid name: " <> Text.unpack
 name) (makeName name)
 }}}

 The problem with this approach is that even though the cause of the
 mistake is a programming error, I don't find out about it until run time.

 What I'd like to do is write an `IsString` instance for `Name` which does
 that validation, e.g.

 {{{#!hs
 instance IsString Name where
   fromString = unsafeMakeName . Text.pack
 }}}

 ... but to get the error about invalid names in literals at compile-time.
 This doesn't seem logically impossible to me, since the compiler could
 know the values of literals with certainty.

--
Ticket URL: <http://ghc.haskell.org/trac/ghc/ticket/13028>
GHC <http://www.haskell.org/ghc/>
The Glasgow Haskell Compiler


More information about the ghc-tickets mailing list