4 ms·
> I'm of the opinion that worked examples are often worse than no documentation. I'm not, especially for the many more-abstract-concepts. I have yet to see a f
by dualogy 10y ago
> I'm of the opinion that worked examples are often worse than no documentation.
I'm not, especially for the many more-abstract-concepts. I have yet to see a followable code case demonstrating the use of custom monads (not IO or Maybe or lists etc) that show why (when) I should ever write my own, to understand even just using them better generally.. A lot of explanations in the Haskell ecosystem are super-abstract and forever-self-referencing and as someone arriving with a sense of urgency of pumping out Brave New Apps to the world, I'm always itching and saying "OK transformables turn foldables that contain applicatives into functors that fold applicatives into transformables so in other words I CAN SKIP THIS RITE?" Leave it in the shadows as it was clearly a priority to neatly have the abstractions that allowed making MayBe/IO/Lists etc as usable language features in there.
On the other hand I don't want to end up writing 10k lines that could have been expressed in 500 had I grasped the more obtuse abstractions.
Experience tells me that once you happen across a simple real-world use, the shocking simplicity of what was encrypted in mathematical-logical-calculi lingo is instantly revealed. The absence of such "code examples" (with a real-world touch, not just x,y,z,f,g,h identifiers in a senseless vacuum) is truly annoying and goes all the way from the Wiki to Diehl's articles to various books.. it's hyperprevalent throughout the community.
- dllthomas 10y ago> I have yet to see a followable code case demonstrating the use of custom monads (not IO or Maybe or lists etc) that show why (when) I should ever write my own, to understand even just using them better generally. For an interpreter I'm working on I have an "Eval" type, implemented as a newtype wrapper around a transformer stack. This gives me a context to work in where I can access variables in scope (carried in a ReaderT) and fail with error (handled by an ExceptT). The code (simplified) looks a little like this: {-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE LambdaExpr #-} newtype Eval a = Eval (Reader EvalContext (ExceptT String m) a) deriving (Functor, Applicative, Monad, MonadReader EvalContext, MonadError String) lookupVariable :: Variable -> Eval Value lookupVariable v = asks (findVarInContext v) >>= \case Nothing -> throwError ("unbound variable: " ++ show v) Just result -> pure result lookupFunction :: FunctionName -> Eval ([Value] -> Value) lookupFunction f = asks (findFuncInContext f) >>= \case Nothing -> throwError ("unknown function: " ++ show f) Just f' -> pure f' evaluateFunction :: Function -> Eval Value evaluateFunction (Function name args) = lookupFunction function <*> mapM evaluateExpr args
- greenrd 10y agoThat looks like more of a combination of existing monads than a truly new monad. I must admit that I can't remember ever creating my own monad from scratch.
- dllthomas 10y ago> That looks like more of a combination of existing monads than a truly new monad. Well sure, but if we're going to exclude those then the grandparent's ask is a bit high: either we present something useless and pedagogic, or we present something useful that exists in a library somewhere, or we present something new and useful... that we should then also put in a library somewhere!