I wrote a utility type and function that is meant to aid in parsing certain row-polymorphic types (sepcifically, in my case, anything that extends BaseIdRows
:
type IdTypePairF r = (identifier :: Foreign, identifierType :: Foreign | r)
readIdTypePair :: forall r. Record (IdTypePairF r) -> F Identifier
readIdTypePair idPairF = do
id <- readNEStringImpl idPairF.identifier
idType <- readNEStringImpl idPairF.identifierType
pure $ {identifier: id, identifierType: idType}
When I try to use it, however, it causes the code to get this type error (in my larger code base, things were working fine before I implemented the readIdTypePair
function):
No type class instance was found for
Prim.RowList.RowToList ( identifier :: Foreign
, identifierType :: Foreign
| t3
)
t4
The instance head contains unknown type variables. Consider adding a type annotation.
while applying a function readJSON'
of type ReadForeign t2 => String -> ExceptT (NonEmptyList ForeignError) Identity t2
to argument jsStr
while checking that expression readJSON' jsStr
has type t0 t1
in value declaration readRecordJSON
where t0 is an unknown type
t1 is an unknown type
t2 is an unknown type
t3 is an unknown type
t4 is an unknown type
I have a live gist that demonstrates my issue.
But, here is the complete example as it stands, for posterity:
module Main where
import Control.Monad.Except (except, runExcept)
import Data.Array.NonEmpty (NonEmptyArray, fromArray)
import Data.Either (Either(..))
import Data.HeytingAlgebra ((&&), (||))
import Data.Lazy (Lazy, force)
import Data.Maybe (Maybe(..))
import Data.Semigroup ((<>))
import Data.String.NonEmpty (NonEmptyString, fromString)
import Data.Traversable (traverse)
import Effect (Effect(..))
import Foreign (F, Foreign, isNull, isUndefined)
import Foreign as Foreign
import Prelude (Unit, bind, pure, ($), (>>=), unit)
import Simple.JSON as JSON
main :: Effect Unit
main = pure unit
type ResourceRows = (
identifiers :: Array Identifier
)
type Resource = Record ResourceRows
type BaseIdRows r = (
identifier :: NonEmptyString
, identifierType :: NonEmptyString
| r
)
type Identifier = Record (BaseIdRows())
-- Utility type for parsing
type IdTypePairF r = (identifier :: Foreign, identifierType :: Foreign | r)
readNEStringImpl :: Foreign -> F NonEmptyString
readNEStringImpl f = do
str :: String <- JSON.readImpl f
except $ case fromString str of
Just nes -> Right nes
Nothing -> Left $ pure $ Foreign.ForeignError
"Nonempty string expected."
readIdTypePair :: forall r. Record (IdTypePairF r) -> F Identifier
readIdTypePair idPairF = do
id <- readNEStringImpl idPairF.identifier
idType <- readNEStringImpl idPairF.identifierType
pure $ {identifier: id, identifierType: idType}
readRecordJSON :: String -> Either Foreign.MultipleErrors Resource
readRecordJSON jsStr = runExcept do
recBase <- JSON.readJSON' jsStr
--foo :: String <- recBase.identifiers -- Just comment to check inferred type
idents :: Array Identifier <- traverse readIdTypePair recBase.identifiers
pure $ recBase { identifiers = idents }