Remix.run Logo
llmslave2 9 hours ago

Agreed. It's often accompanied by the dogma "make invalid states unrepresentable" which sounds good until you start trying to encode into the type system foo.bar being 1-42 unless foo.baz is above 10, where now foo.bar can be -42-1 instead, but if foo.omfg is prefixed with "wtf" then foo.baz needs to be above 20 for its modifiers to kick in.

Yeah good luck doing that in the type system in a way that is maintainable, open to modification, an scales with complexity.

kccqzy 5 hours ago | parent [-]

You have misunderstood what it means to make invalid states unrepresentable.

    data UnvalidatedFoo = UnvalidatedFoo
      { unvalidatedOmfg :: String,
        unvalidatedBar, unvalidatedBaz :: Int
      }
    
    data ValidatedFoo = ValidatedFoo
      { validatedOmfg :: String,
        validatedBar, validatedBaz :: Int
      }
    
    validate :: UnvalidatedFoo -> Maybe ValidatedFoo
    validate UnvalidatedFoo {..} = do
      when ("wtf" `isPrefixOf` unvalidatedOmfg) $ do
        guard (unvalidatedBaz > 20)
      if unvalidatedBaz > 10
        then guard (unvalidatedBar >= 1 && unvalidatedBar <= 42)
        else guard (unvalidatedBar >= -42 && unvalidatedBar <= 1)
      pure ValidatedFoo {validatedOmfg = unvalidatedOmfg, validatedBaz = unvalidatedBaz, validatedBar = unvalidatedBar}