PureScript's IsForeign typeclass is used to take any foreign value (a value whose type is unknown by the compiler) and turn it into a type the compiler recognizes. This usually happens when you're interacting with native javascript or an API.
Created
March 4, 2017 21:18
-
-
Save dgendill/25bbf4cf8a13c7489eefeaba2f10c82a to your computer and use it in GitHub Desktop.
Using PureScript's IsForeign class to parse a Point type from a String
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module Main where | |
import Prelude | |
import Control.Monad.Eff (Eff) | |
import Control.Monad.Eff.Console (CONSOLE, log, logShow) | |
import Control.Monad.Except (runExcept, throwError) | |
import Data.Array (head, last, length) | |
import Data.Either (Either(Right, Left)) | |
import Data.Foldable (traverse_) | |
import Data.Foreign (F, ForeignError(..), readString, toForeign) | |
import Data.Foreign.Class (class IsForeign, read) | |
import Data.Generic (class Generic, gEq, gShow) | |
import Data.Int (fromString) | |
import Data.List.NonEmpty (singleton) | |
import Data.Maybe (Maybe(..)) | |
import Data.String (Pattern(..), split) | |
-- Create a newtype wrapper for a Point and derive | |
-- Generic, Eq and Show instances for it... | |
newtype Point = Point { x :: Int, y :: Int } | |
derive instance gPoint :: Generic Point | |
instance eqPoint :: Eq Point where eq = gEq | |
instance showPoint :: Show Point where show = gShow | |
-- IsForeign class defines the read function that | |
-- takes a foreign value (a value that we don't know | |
-- what it is), and attempts to return the type that we | |
-- want - in this case a Point | |
instance fPoint :: IsForeign Point where | |
read value = do | |
s <- readString value | |
let parts = split (Pattern ",") s | |
if (length parts) == 2 | |
then do | |
let | |
mp = do | |
x <- (head parts >>= fromString) | |
y <- (last parts >>= fromString) | |
pure $ Point {x : x, y : y} | |
case mp of | |
Nothing -> throwError $ singleton (ForeignError "Could not parse Point from string.") | |
Just p -> pure p | |
else throwError $ singleton (ForeignError "Could not parse Point from string.") | |
runParse :: String -> Eff (console :: CONSOLE) Unit | |
runParse value = do | |
log $ "Parsing " <> value | |
-- Since read can parse any foreign value into | |
-- any type, we have to explicitly specify the | |
-- type we intend to read. | |
let a = runExcept $ read (toForeign value) :: F Point | |
case a of | |
Left e -> traverse_ logShow e | |
Right r -> log $ "Successful Parse: " <> (show a) | |
main :: Eff (console :: CONSOLE) Unit | |
main = do | |
runParse "11" | |
runParse "10,10" | |
runParse "a,b" | |
runParse "6,6,c" |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Parsing 11 | |
(ForeignError Could not parse Point from string.) | |
Parsing 10,10 | |
Successful Parse: (Right Main.Point {x: 10, y: 10}) | |
Parsing a,b | |
(ForeignError Could not parse Point from string.) | |
Parsing 6,6,c | |
(ForeignError Could not parse Point from string.) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment