Nevoic
@Nevoic@lemmy.world
- Comment on Golang be like 1 year ago:
This isn’t a language level issue really though, Haskell can be equally ergonomic.
The weird thing about
?.
is that it’s actually overloaded, it can mean:- call a function on
A?
that returnsB?
- call a function on
A?
that returnsB
you’d end up with
B?
in either caseSay you have these functions
toInt :: String -> Maybe Int double :: Int -> Int isValid :: Int -> Maybe Int
and you want to construct the following using these 3 functions
fn :: Maybe String -> Maybe Int
in a Rust-type syntax, you’d call
str?.toInt()?.double()?.isValid()
in Haskell you’d have two different operators here
str >>= toInt <&> double >>= isValid
however you can define this type class
class Chainable f a b fb where (?.) :: f a -> (a -> fb) -> f b instance Functor f => Chainable f a b b where (?.) = (<&>) instance Monad m => Chainable m a b (m b) where (?.) = (>>=)
and then get roughly the same syntax as rust without introducing a new language feature
str ?. toInt ?. double ?. isValid
though this is more general than just
Maybe
s (it works with any functor/monad), and maybe you wouldn’t want it to be. In that case you’d do thisclass Chainable a b fb where (?.) :: Maybe a -> (a -> fb) -> Maybe b instance Chainable a b b where (?.) = (<&>) instance Chainable a b (Maybe b) where (?.) = (>>=)
restricting it to only maybes could also theoretically help type inference.
- call a function on
- Comment on Golang be like 1 year ago:
Here’s an example (first in Haskell then in Go), lets say you have some types/functions:
- type Possible a = Either String a
- data User = User { name :: String, age :: Int }
- validateName :: String -> Possible String
- validateAge :: Int -> Possible Int
then you can make:
mkValidUser :: String -> Int -> Possible User mkValidUser name age = do validatedName <- validateName name validatedAge <- validateAge age pure $ User validatedName validatedAge
in Go you’d have these
- (no
Possible
type alias, Go can’t do generic type aliases yet, there’s an open issue for it) - type User struct { Name string; Age int }
- func validateName(name string) (string, error)
- func validateAge(age int) (int, error)
and with them you’d make:
func mkValidUser(name string, age int) (*User, error) { validatedName, err = validateName(name) if err != nil { return err } validatedAge, err = validateAge(age) if err != nil { return err } return User(Name: validatedName, Age: validatedAge) }
In the Haskell, the fact that
Either
is a monad is saving you from a lot of boilerplate. You don’t have to explicitly handle theLeft
/error case, if any of theEither
s end up being aLeft
value then it’ll correctly “short-circuit” and the function will evaluate to thatLeft
value.Without using the fact that it’s a functor/monad (e.g you have no access to fmap/>>=/do syntax), you’d end up with code that has a similar amount of boilerplate to the Go code (notice we have to handle each
Left
case now):mkValidUser :: String -> Int -> Possible User mkValidUser name age = case (validatedName name, validateAge age) of (Left nameErr, _) => Left nameErr (_, Left ageErr) => Left ageErr (Right validatedName, Right validatedAge) => Right $ User validatedName validatedAge
- Comment on Unpacking Google’s new “dangerous” Web-Environment-Integrity specification 1 year ago:
Over 85% of Mozilla’s income comes from their Google search deal. Google is keeping Mozilla alive to prevent antitrust issues. If Mozilla rocks the boat too much, Google will fund a more obedient alternative.