لا ، أنظمة النوع الديناميكي لم تعد مفتوحة بشكل أساسي

لا تزال الحروب المقدسة على الإنترنت حول أنظمة الكتابة تعاني من الأسطورة المنتشرة بأن أنظمة الكتابة الديناميكية مناسبة بطبيعتها لنمذجة مجالات الموضوعات في "العالم المفتوح". عادة ما تكون الحجة هي: الغرض من الكتابة الثابتة هو التقاط جميع الكيانات بأكبر قدر ممكن من الدقة ، ولكن في العالم الحقيقي هذا ببساطة غير مريح. يجب أن تقترن الأنظمة الحقيقية بشكل فضفاض وأن تكون أقل قدر ممكن مرتبطة بعرض البيانات ، لذا فإن الكتابة الديناميكية تؤدي إلى نظام أكثر استقرارًا ككل.



تبدو هذه القصة مقنعة ، لكنها ليست صحيحة. الخطأ في مثل هذا المنطق هو أن الأنواع الثابتة لا تهدف إلى "تصنيف العالم" أو تحديد هيكل كل قيمة في النظام. والحقيقة هي أن أنظمة النوع الثابت تسمح لك بتحديد مقدار ما يجب أن يعرفه المكون بالضبط حول بنية بيانات الإدخال الخاصة به ، وبالعكس ، كم لا يعرف. من الناحية العملية ، تقوم أنظمة النوع الثابت بمعالجة البيانات بشكل مثالي مع بنية معروفة جزئيًا ، بالإضافة إلى القدرة على التأكد من أن منطق التطبيق لا يفترض عن غير قصد الكثير عن البيانات.


كذبان حول الأنواع


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