Skip to content

Commit ad52524

Browse files
felixSchlFelix Schlitterthomashoneyman
authored
Introduce monad transformer FT (#74)
Co-authored-by: Felix Schlitter <[email protected]> Co-authored-by: Thomas Honeyman <[email protected]>
1 parent 32032a0 commit ad52524

File tree

3 files changed

+31
-30
lines changed

3 files changed

+31
-30
lines changed

src/Foreign.purs

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ module Foreign
66
, ForeignError(..)
77
, MultipleErrors(..)
88
, F
9+
, FT
910
, renderForeignError
1011
, unsafeToForeign
1112
, unsafeFromForeign
@@ -29,7 +30,7 @@ module Foreign
2930

3031
import Prelude
3132

32-
import Control.Monad.Except (Except, throwError, mapExcept)
33+
import Control.Monad.Except (Except, ExceptT, mapExceptT, throwError)
3334
import Data.Either (Either(..), either)
3435
import Data.Int as Int
3536
import Data.List.NonEmpty (NonEmptyList)
@@ -81,6 +82,7 @@ renderForeignError (TypeMismatch exp act) = "Type mismatch: expected " <> exp <>
8182
-- | The `Alt` instance for `Except` allows us to accumulate errors,
8283
-- | unlike `Either`, which preserves only the last error.
8384
type F = Except MultipleErrors
85+
type FT = ExceptT MultipleErrors
8486

8587
-- | Coerce any value to the a `Foreign` value.
8688
-- |
@@ -105,7 +107,7 @@ foreign import tagOf :: Foreign -> String
105107

106108
-- | Unsafely coerce a `Foreign` value when the value has a particular `tagOf`
107109
-- | value.
108-
unsafeReadTagged :: forall a. String -> Foreign -> F a
110+
unsafeReadTagged :: forall m a. Monad m => String -> Foreign -> FT m a
109111
unsafeReadTagged tag value
110112
| tagOf value == tag = pure (unsafeFromForeign value)
111113
| otherwise = fail $ TypeMismatch tag (tagOf value)
@@ -120,52 +122,52 @@ foreign import isUndefined :: Foreign -> Boolean
120122
foreign import isArray :: Foreign -> Boolean
121123

122124
-- | Attempt to coerce a foreign value to a `String`.
123-
readString :: Foreign -> F String
125+
readString :: forall m. Monad m => Foreign -> FT m String
124126
readString = unsafeReadTagged "String"
125127

126128
-- | Attempt to coerce a foreign value to a `Char`.
127-
readChar :: Foreign -> F Char
128-
readChar value = mapExcept (either (const error) fromString) (readString value)
129+
readChar :: forall m. Monad m => Foreign -> FT m Char
130+
readChar value = mapExceptT (map $ either (const error) fromString) (readString value)
129131
where
130132
fromString = maybe error pure <<< toChar
131133
error = Left $ NEL.singleton $ TypeMismatch "Char" (tagOf value)
132134

133135
-- | Attempt to coerce a foreign value to a `Boolean`.
134-
readBoolean :: Foreign -> F Boolean
136+
readBoolean :: forall m. Monad m => Foreign -> FT m Boolean
135137
readBoolean = unsafeReadTagged "Boolean"
136138

137139
-- | Attempt to coerce a foreign value to a `Number`.
138-
readNumber :: Foreign -> F Number
140+
readNumber :: forall m. Monad m => Foreign -> FT m Number
139141
readNumber = unsafeReadTagged "Number"
140142

141143
-- | Attempt to coerce a foreign value to an `Int`.
142-
readInt :: Foreign -> F Int
143-
readInt value = mapExcept (either (const error) fromNumber) (readNumber value)
144+
readInt :: forall m. Monad m => Foreign -> FT m Int
145+
readInt value = mapExceptT (map $ either (const error) fromNumber) (readNumber value)
144146
where
145147
fromNumber = maybe error pure <<< Int.fromNumber
146148
error = Left $ NEL.singleton $ TypeMismatch "Int" (tagOf value)
147149

148150
-- | Attempt to coerce a foreign value to an array.
149-
readArray :: Foreign -> F (Array Foreign)
151+
readArray :: forall m. Monad m => Foreign -> FT m (Array Foreign)
150152
readArray value
151153
| isArray value = pure $ unsafeFromForeign value
152154
| otherwise = fail $ TypeMismatch "array" (tagOf value)
153155

154-
readNull :: Foreign -> F (Maybe Foreign)
156+
readNull :: forall m. Monad m => Foreign -> FT m (Maybe Foreign)
155157
readNull value
156158
| isNull value = pure Nothing
157159
| otherwise = pure (Just value)
158160

159-
readUndefined :: Foreign -> F (Maybe Foreign)
161+
readUndefined :: forall m. Monad m => Foreign -> FT m (Maybe Foreign)
160162
readUndefined value
161163
| isUndefined value = pure Nothing
162164
| otherwise = pure (Just value)
163165

164-
readNullOrUndefined :: Foreign -> F (Maybe Foreign)
166+
readNullOrUndefined :: forall m. Monad m => Foreign -> FT m (Maybe Foreign)
165167
readNullOrUndefined value
166168
| isNull value || isUndefined value = pure Nothing
167169
| otherwise = pure (Just value)
168170

169-
-- | Throws a failure error in `F`.
170-
fail :: forall a. ForeignError -> F a
171+
-- | Throws a failure error in `FT`.
172+
fail :: forall m a. Monad m => ForeignError -> FT m a
171173
fail = throwError <<< NEL.singleton

src/Foreign/Index.purs

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -17,37 +17,36 @@ import Prelude
1717

1818
import Control.Monad.Except.Trans (ExceptT)
1919

20-
import Foreign (Foreign, F, ForeignError(..), typeOf, isUndefined, isNull, fail)
20+
import Foreign (Foreign, FT, ForeignError(..), typeOf, isUndefined, isNull, fail)
2121
import Data.Function.Uncurried (Fn2, runFn2, Fn4, runFn4)
22-
import Data.Identity (Identity)
2322
import Data.List.NonEmpty (NonEmptyList)
2423

2524
-- | This type class identifies types that act like _property indices_.
2625
-- |
2726
-- | The canonical instances are for `String`s and `Int`s.
28-
class Index i where
29-
index :: Foreign -> i -> F Foreign
27+
class Index i m | i -> m where
28+
index :: Foreign -> i -> FT m Foreign
3029
hasProperty :: i -> Foreign -> Boolean
3130
hasOwnProperty :: i -> Foreign -> Boolean
3231
errorAt :: i -> ForeignError -> ForeignError
3332

34-
class Indexable a where
35-
ix :: forall i. Index i => a -> i -> F Foreign
33+
class Indexable a m | a -> m where
34+
ix :: forall i. Index i m => a -> i -> FT m Foreign
3635

3736
infixl 9 ix as !
3837

3938
foreign import unsafeReadPropImpl :: forall r k. Fn4 r (Foreign -> r) k Foreign r
4039

41-
unsafeReadProp :: forall k. k -> Foreign -> F Foreign
40+
unsafeReadProp :: forall k m. Monad m => k -> Foreign -> FT m Foreign
4241
unsafeReadProp k value =
4342
runFn4 unsafeReadPropImpl (fail (TypeMismatch "object" (typeOf value))) pure k value
4443

4544
-- | Attempt to read a value from a foreign value property
46-
readProp :: String -> Foreign -> F Foreign
45+
readProp :: forall m. Monad m => String -> Foreign -> FT m Foreign
4746
readProp = unsafeReadProp
4847

4948
-- | Attempt to read a value from a foreign value at the specified numeric index
50-
readIndex :: Int -> Foreign -> F Foreign
49+
readIndex :: forall m. Monad m => Int -> Foreign -> FT m Foreign
5150
readIndex = unsafeReadProp
5251

5352
foreign import unsafeHasOwnProperty :: forall k. Fn2 k Foreign Boolean
@@ -66,20 +65,20 @@ hasPropertyImpl _ value | isUndefined value = false
6665
hasPropertyImpl p value | typeOf value == "object" || typeOf value == "function" = runFn2 unsafeHasProperty p value
6766
hasPropertyImpl _ value = false
6867

69-
instance indexString :: Index String where
68+
instance indexString :: Monad m => Index String m where
7069
index = flip readProp
7170
hasProperty = hasPropertyImpl
7271
hasOwnProperty = hasOwnPropertyImpl
7372
errorAt = ErrorAtProperty
7473

75-
instance indexInt :: Index Int where
74+
instance indexInt :: Monad m => Index Int m where
7675
index = flip readIndex
7776
hasProperty = hasPropertyImpl
7877
hasOwnProperty = hasOwnPropertyImpl
7978
errorAt = ErrorAtIndex
8079

81-
instance indexableForeign :: Indexable Foreign where
80+
instance indexableForeign :: Monad m => Indexable Foreign m where
8281
ix = index
8382

84-
instance indexableExceptT :: Indexable (ExceptT (NonEmptyList ForeignError) Identity Foreign) where
83+
instance indexableExceptT :: Monad m => Indexable (ExceptT (NonEmptyList ForeignError) m Foreign) m where
8584
ix f i = flip index i =<< f

src/Foreign/Keys.purs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,12 @@ module Foreign.Keys
77

88
import Prelude
99

10-
import Foreign (F, Foreign, ForeignError(..), typeOf, isUndefined, isNull, fail)
10+
import Foreign (FT, Foreign, ForeignError(..), typeOf, isUndefined, isNull, fail)
1111

1212
foreign import unsafeKeys :: Foreign -> Array String
1313

1414
-- | Get an array of the properties defined on a foreign value
15-
keys :: Foreign -> F (Array String)
15+
keys :: forall m. Monad m => Foreign -> FT m (Array String)
1616
keys value
1717
| isNull value = fail $ TypeMismatch "object" "null"
1818
| isUndefined value = fail $ TypeMismatch "object" "undefined"

0 commit comments

Comments
 (0)