рдЯрд╛рдЗрдк рд╕рд┐рд╕реНрдЯрдо рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдЗрдВрдЯрд░рдиреЗрдЯ рдкрд░ рдкрд╡рд┐рддреНрд░ рдпреБрджреНрдз рд╡реНрдпрд╛рдкрдХ рдорд┐рдердХ рд╕реЗ рдЧреНрд░рд╕реНрдд рд╣реИрдВ рдХрд┐ рдЧрддрд┐рд╢реАрд▓ рдкреНрд░рдХрд╛рд░ рдХреА рдкреНрд░рдгрд╛рд▓рд┐рдпрд╛рдВ "рдЦреБрд▓реА рджреБрдирд┐рдпрд╛" рдХреЗ рд╡рд┐рд╖рдп рдХреНрд╖реЗрддреНрд░реЛрдВ рдХреЗ рд▓рд┐рдП рд╕реНрд╡рд╛рднрд╛рд╡рд┐рдХ рд░реВрдк рд╕реЗ рдмреЗрд╣рддрд░ рдЕрдиреБрдХреВрд▓ рд╣реИрдВред рдЖрдорддреМрд░ рдкрд░ рддрд░реНрдХ рдпрд╣ рд╣реИ: рд╕реНрдерд┐рд░ рдЯрд╛рдЗрдкрд┐рдВрдЧ рдХрд╛ рдЙрджреНрджреЗрд╢реНрдп рд╕рднреА рд╕рдВрд╕реНрдерд╛рдУрдВ рдХреЛ рдпрдерд╛рд╕рдВрднрд╡ рд╕рдЯреАрдХ рд░реВрдк рд╕реЗ рдкрдХрдбрд╝рдирд╛ рд╣реИ, рд▓реЗрдХрд┐рди рд╡рд╛рд╕реНрддрд╡рд┐рдХ рджреБрдирд┐рдпрд╛ рдореЗрдВ рдпрд╣ рдХреЗрд╡рд▓ рдЕрд╕реБрд╡рд┐рдзрд╛рдЬрдирдХ рд╣реИред рд╡рд╛рд╕реНрддрд╡рд┐рдХ рдкреНрд░рдгрд╛рд▓рд┐рдпреЛрдВ рдХреЛ рд╢рд┐рдерд┐рд▓ рдпреБрдЧреНрдорд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рдирд╛ рдЪрд╛рд╣рд┐рдП рдФрд░ рдЬрд┐рддрдирд╛ рд╕рдВрднрд╡ рд╣реЛ рдЙрддрдирд╛ рдХрдо рдбреЗрдЯрд╛ рдХреА рдкреНрд░рд╕реНрддреБрддрд┐ рд╕реЗ рдмрдВрдзрд╛ рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдП, рдЗрд╕рд▓рд┐рдП рдЧрддрд┐рд╢реАрд▓ рдЯрд╛рдЗрдкрд┐рдВрдЧ рдПрдХ рдкреВрд░реЗ рдХреЗ рд░реВрдк рдореЗрдВ рдЕрдзрд┐рдХ рд╕реНрдерд┐рд░ рдкреНрд░рдгрд╛рд▓реА рдХреА рдУрд░ рдЬрд╛рддрд╛ рд╣реИред

рдпрд╣ рдХрд╣рд╛рдиреА рдХрд╛рдпрд▓ рд╣реИ, рд▓реЗрдХрд┐рди рдпрд╣ рд╕рдЪ рдирд╣реАрдВ рд╣реИред рдЗрд╕ рддрд░рд╣ рдХреЗ рддрд░реНрдХ рдореЗрдВ рдЧрд▓рддреА рдпрд╣ рд╣реИ рдХрд┐ рд╕реНрдерд┐рд░ рдкреНрд░рдХрд╛рд░реЛрдВ рдХрд╛ рдЙрджреНрджреЗрд╢реНрдп "рджреБрдирд┐рдпрд╛ рдХреЛ рд╡рд░реНрдЧреАрдХреГрдд рдХрд░рдирд╛ " рдирд╣реАрдВ рд╣реИ рдпрд╛ рд╕рд┐рд╕реНрдЯрдо рдореЗрдВ рдкреНрд░рддреНрдпреЗрдХ рдореВрд▓реНрдп рдХреА рд╕рдВрд░рдЪрдирд╛ рдХрд╛ рдирд┐рд░реНрдзрд╛рд░рдг рдХрд░рдирд╛ рд╣реИред рд╡рд╛рд╕реНрддрд╡рд┐рдХрддрд╛ рдпрд╣ рд╣реИ рдХрд┐ рд╕реНрдерд┐рд░ рдкреНрд░рдХрд╛рд░ рдХреА рдкреНрд░рдгрд╛рд▓рд┐рдпрд╛рдВ рдЖрдкрдХреЛ рдпрд╣ рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддреА рд╣реИрдВ рдХрд┐ рдХрд┐рд╕реА рдШрдЯрдХ рдХреЛ рдЕрдкрдиреЗ рдЗрдирдкреБрдЯ рдбреЗрдЯрд╛ рдХреА рд╕рдВрд░рдЪрдирд╛ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдХрд┐рддрдирд╛ рдкрддрд╛ рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдП, рдФрд░, рдЗрд╕рдХреЗ рд╡рд┐рдкрд░реАрдд, рдпрд╣ рдХрд┐рддрдирд╛ рдирд╣реАрдВ рдЬрд╛рдирддрд╛ рд╣реИред рд╡реНрдпрд╡рд╣рд╛рд░ рдореЗрдВ, рд╕реНрдереИрддрд┐рдХ рдкреНрд░рдХрд╛рд░ рд╕рд┐рд╕реНрдЯрдо рдЖрдВрд╢рд┐рдХ рд░реВрдк рд╕реЗ рдЬреНрдЮрд╛рдд рд╕рдВрд░рдЪрдирд╛ рдХреЗ рд╕рд╛рде рдбреЗрдЯрд╛ рдХреЛ рдкреВрд░реА рддрд░рд╣ рд╕реЗ рд╕рдВрд╕рд╛рдзрд┐рдд рдХрд░рддреЗ рд╣реИрдВ, рд╕рд╛рде рд╣реА рдпрд╣ рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдХрд░рдиреЗ рдореЗрдВ рд╕рдХреНрд╖рдо рд╣реЛрддреЗ рд╣реИрдВ рдХрд┐ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рддрд░реНрдХ рдЧрд▓рддреА рд╕реЗ рдбреЗрдЯрд╛ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдмрд╣реБрдд рдЕрдзрд┐рдХ рдирд╣реАрдВ рдорд╛рдирддрд╛ рд╣реИред
рджреЛ рдкреНрд░рдХрд╛рд░ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдЭреВрда
, . , , /r/programming:
[тАж], . , , ┬л┬╗ , , - .
, , . JSON , . , . [тАж] ┬л ┬╗ , .
, , , , . , - , , ? , , .
Hacker News :
, , pickle.load()
?
, , , . , , .
, , . , , : . , ; , .
,
: , , , , ! , . , .
. , , . (payload), . , - , JSON EDN.
, , :
{
"event_type": "signup",
"timestamp": "2020-01-19T05:37:09Z",
"data": {
"user": {
"id": 42,
"name": "Alyssa",
"email": "alyssa@example.com"
}
}
}
signup
- . , . JavaScript, :
const handleEvent = ({ event_type, data }) => {
switch (event_type) {
case 'login':
/* ... */
break
case 'signup':
sendEmail(data.user.email, `Welcome to Blockchain Emporium, ${data.user.name}!`)
break
}
}
, Haskell? , Haskell, , , :
data Event = Login LoginPayload | Signup SignupPayload
data LoginPayload = LoginPayload { userId :: Int }
data SignupPayload = SignupPayload
{ userId :: Int
, userName :: Text
, userEmail :: Text
}
instance FromJSON Event where
parseJSON = withObject "Event" \obj -> do
eventType <- obj .: "event_type"
case eventType of
"login" -> Login <$> (obj .: "data")
"signup" -> Signup <$> (obj .: "signup")
_ -> fail $ "unknown event_type: " <> eventType
instance FromJSON LoginPayload where { ... }
instance FromJSON SignupPayload where { ... }
handleEvent :: JSON.Value -> IO ()
handleEvent payload = case fromJSON payload of
Success (Login LoginPayload { userId }) -> {- ... -}
Success (Signup SignupPayload { userName, userEmail }) ->
sendEmail userEmail $ "Welcome to Blockchain Emporium, " <> userName <> "!"
Error message -> fail $ "could not parse event: " <> message
, (, , ). . , Reddit, , Haskell , ! Event, . , ? .
, JavaScript . , switch
. , JavaScript . , .
, , . Event
, , handleEvent
. JavaScript, , :
const handleEvent = ({ event_type, data }) => {
switch (event_type) {
/* ... */
default:
throw new Error(`unknown event_type: ${event_type}`)
}
}
, . , , . , , Haskell:
handleEvent :: JSON.Value -> IO ()
handleEvent payload = case fromJSON payload of
{- ... -}
Error _ -> pure ()
- ┬л, ┬╗, , . , ( ) . , ! , .
: Event
Haskell ┬л ┬╗, , . , , . , , , .
, , , :
Haskell, . , , timestamp
, . , , , , , !
, , Haskell userId
SignupPayload
, . , (, , userId
), ; , , , .
, , (shotgun parsing), , .
, , , , , . , , . , , , , , , .
JavaScript , Haskell: , JSON event_type
┬л┬╗ signup
data.user.name
data.user.email
. ! , JavaScript , . , ; , , - .
, , , , .
, , , - -. , , . , . JavaScript :
const handleEvent = (payload) => {
const signedPayload = { ...payload, signature: signature(payload) }
retransmitEvent(signedPayload)
}
( signature JSON), , . , ?
, : , . Haskell:
handleEvent :: JSON.Value -> IO ()
handleEvent (Object payload) = do
let signedPayload = Map.insert "signature" (signature payload) payload
retransmitEvent signedPayload
handleEvent payload = fail $ "event payload was not an object " <> show payload
, , JSON.Value
. Event
тАФ JSON , , .
: , JSON- ( -), - JSON, - . , , , , . .
, , Haskell, JavaScript! JavaScript handleEvent
( JSON ), , , , spread- тАж
:
> { ..."payload", signature: "sig" }
{0: "p", 1: "a", 2: "y", 3: "l", 4: "o", 5: "a", 6: "d", signature: "sig"}
, . , . ┬л┬╗ JSON Object
, . -, , .
, . , API, , , UUID
. ┬л, ┬╗ , API Haskell UUID
:
type UserId = UUID
, Reddit, , ! API , UUID, , . UUID , , , ! , ?
, тАФ . , тАФ . , UserId
тАФ :
newtype UserId = UserId Text
deriving (Eq, FromJSON, ToJSON)
, UUID
, UserId
, , Text
. ( , ), UserId
тАФ FromJSON
. , , UserId
тАФ UserId
ToJSON
. : .
, , . UserId
, UserId
.
1, FromJSON
UserId
, , , fromJSON
. , - . , , тАж UserId
. , , ( , , , ).
тАФ , . , , , .
-
, , , , , . pickle.load()
Python? , , Python. pickle.dump()
, pickle.load()
.
, , pickle.load()
, тАФ , pickle.dump()
. , , . , , , .
, JSON, , pickle Python Python , . ? , , pickle.load()
. , :
def load_value(f):
val = pickle.load(f)
# - `val`
, val
, , , , , - . - - , , pickle.load(f)
, , val
!
, , , val
val.foo()
, . Java, val
тАФ , :
interface Foo extends Serializable {
String foo();
}
, pickle.load()
Java:
static <T extends Serializable> Optional<T> load(InputStream in, Class<? extends T> cls);
, , pickle.load()
, Class<T>
. Serializable.class
, . : , -, - , ! , , JSON-.
Haskell? тАФ serialise, API, , Java, . API , Haskell JSON, aeson, , , JSON Haskell тАФ - - , -.
, , pickle.load()
, . , . - , , , , . , (, REPL ), , .
. , , , , - , ┬л┬╗ , , . , , , , , .
. , , , ( ). , , ┬л┬╗ .
: ,
: . , , , , , .
, , . -, - (nominal typing). , , , , . , . , .
, , , , . , , -, , ( ).
. JavaScript Clojure - , - , . ( ) .
, , - , , . ( ) , (nominal typing). , ; (boilerplate).
, , . , , , . , :
, , , , . ( ), : , .
, , - . , , , . , .
Python, , , , TypeScript, , . , . - Clojure тАФ , - тАФ , - Clojure, - .
, : TypeScript, Flow, PureScript, Elm, OCaml Reason, . тАФ Haskell, ; Haskell ( , ) .
, Haskell , ? , ; Haskell, , . Haskell, , . , Haskell, , , . ( , , Haskell!)
: , , , . , , , . тАФ , , , , . .