Nein, dynamische Systeme sind im Wesentlichen nicht mehr offen

Heilige Kriege im Internet über Typensysteme leiden weiterhin unter dem weit verbreiteten Mythos, dass dynamische Typsysteme von Natur aus besser für die Modellierung von Themenbereichen der „offenen Welt“ geeignet sind. Normalerweise lautet das Argument: Der Zweck der statischen Typisierung besteht darin, alle Entitäten so genau wie möglich zu erfassen, aber in der realen Welt ist dies einfach unpraktisch. Reale Systeme sollten lose gekoppelt und so wenig wie möglich an die Darstellung von Daten gebunden sein. Daher führt die dynamische Typisierung zu einem insgesamt stabileren System.



Diese Geschichte klingt überzeugend, ist aber nicht wahr. Der Fehler bei solchen Überlegungen besteht darin, dass statische Typen nicht dazu gedacht sind , die Welt zu klassifizieren oder die Struktur jedes Werts im System zu bestimmen. In Wirklichkeit können Sie mit statischen Typsystemen genau angeben, wie viel eine Komponente über die Struktur ihrer Eingabedaten wissen soll und umgekehrt, wie viel sie nicht weiß. In der Praxis verarbeiten statische Systeme Daten perfekt mit einer teilweise bekannten Struktur und können sicherstellen, dass die Anwendungslogik nicht versehentlich zu viel von den Daten annimmt.


Zwei LĂĽgen ĂĽber Typen


, . , , /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).


, , . , , , . , :


  1. , , , , . ( ), : , .


  2. , , - . , , , . , .



Python, , , , TypeScript, , . , . - Clojure — , - — , - Clojure, - .


, : TypeScript, Flow, PureScript, Elm, OCaml Reason, . — Haskell, ; Haskell ( , ) .


2

, Haskell .


, Haskell , ? , ; Haskell, , . Haskell, , . , Haskell, , , . ( , , Haskell!)


: , , , . , , , . — , , , , . .

Source: https://habr.com/ru/post/undefined/


All Articles