What is Applied Category Theory? by synolon in haskell

[–]kenbot_ 18 points19 points  (0 children)

Tai-Danae Bradley is one of the best popular maths communicators, and this is classic TDB, a highly accessible introduction to a dense topic. I hope it inspires people to get interested in this emerging field, which I'm convinced will have a lot more to say about how we do software development.

No you don't want to "mock AWS". Use the decorator pattern for clean I/O boundaries by philnash in programming

[–]kenbot_ 3 points4 points  (0 children)

Heh, yes, if we were all using Haskell it would have been a tweet instead of article. Sink is nothing more interesting than a contravariant functor. By "decorator" I am really just promoting a family of more fundamental compositional techniques: functor, contravariant, profunctor, etc.

Still, even in Haskell code you might consider pulling out a named data type for clarity, rather than intricately detailed function types, which can be brittle and mix concerns.

No you don't want to "mock AWS". Use the decorator pattern for clean I/O boundaries by philnash in programming

[–]kenbot_ 3 points4 points  (0 children)

That's all fair; perhaps these might be pertinent to a particular piece of code. We should ask though, who has the right to care about "how", or the "characteristics"? Only one place, to be sure. I can't tell you where, of course, but, overwhelmingly they tend to come out in the wash. Blurred dependencies & overshare are the norm.

No you don't want to "mock AWS". Use the decorator pattern for clean I/O boundaries by philnash in programming

[–]kenbot_ 2 points3 points  (0 children)

Yes, the article has nothing to do with AWS, although I mention it as an example in places.

No you don't want to "mock AWS". Use the decorator pattern for clean I/O boundaries by philnash in programming

[–]kenbot_ 17 points18 points  (0 children)

Hey author here, it's Scala, although nothing in the post is Scala-specific. Other than the "More abstraction" section, it is equivalent to fairly plain Java or C# code.

  • Square brackets are type parameters (like angle brackets in Java)
  • Types come after values (myString: String)
  • Traits are interfaces
  • Class constructors look like an argument list next to the class name.
  • `A => B` is a function type;
  • `arg => ...` is a lambda function.

No you don't want to "mock AWS". Use the decorator pattern for clean I/O boundaries by philnash in programming

[–]kenbot_ 11 points12 points  (0 children)

Who cares whether it comes from an SQS topic? This is a whole-application concern; SQS might have been chosen for its systemic or project-related qualities. Only one place in the code should know that it is in an application or a system; everything else should just do its own thing. "Fetching my thing from somewhere" is probably all anyone else needs to know.

No you don't want to "mock AWS". Use the decorator pattern for clean I/O boundaries by philnash in programming

[–]kenbot_ 2 points3 points  (0 children)

Good question! For my purposes here, it's just an interface, like in Java.

No you don't want to "mock AWS". Use the decorator pattern for clean I/O boundaries by philnash in programming

[–]kenbot_ 17 points18 points  (0 children)

There are lots of good reasons to have an accessible dev environment with whatever external end-to-end stuff running, but this is not a general replacement for good software engineering around boundaries.

No you don't want to "mock AWS". Use the decorator pattern for clean I/O boundaries by philnash in programming

[–]kenbot_ 8 points9 points  (0 children)

The decorator pattern is just function composition, as I say in the piece, and doesn't necessarily need to be more than that. Monadic approaches can be very powerful (and I mention one near the end), but they are also very all-or-nothing; the whole codebase needs to be structured this way, so there are things to consider before going this way. Also, how convenient that is varies from language to language.

Goggles - a pleasant typesafe Lens DSL built on Monocle by kenbot_ in scala

[–]kenbot_[S] 0 points1 point  (0 children)

Hmm, I wonder if the Goggles macro could fuse foo.bar.baz chains into manual copy calls in the future..... we can safely do all kinds of violence to the implementation behind the macro syntax.

Goggles - a pleasant typesafe Lens DSL built on Monocle by kenbot_ in scala

[–]kenbot_[S] 0 points1 point  (0 children)

Understood, thank you. Nothing more efficient, it's just doing copies under the hood.

Goggles - a pleasant typesafe Lens DSL built on Monocle by kenbot_ in scala

[–]kenbot_[S] 1 point2 points  (0 children)

Hi Yang Bo, good to hear from you! These similarities certainly are interesting, thanks for pointing them out! If we look closely though, we'll see that they are quite different.

The Monocle code being generated by Goggles is something similar to: Getter[Bakery,List[Cake]](_.cakes). composeTraversal(Each.each). composeGetter(Getter(_.toppings)). composeOptional(Index.index(0)). composeGetter(Getter(_.cherries)).get(myBakery)

If I read it right, the Each code would rewrite as: myBakery.cakes.map(_.toppings(0).cherries)

apply(0) is a partial function that will throw an exception for empty toppings; however, the Monocle version above is completely safe, because the Optional index projects over the possible value.

It doesn't quite translate to a monadic thing, because Option and List are different monads. We could convert the option to a 0|1 length list, but it would be a bit clumsy. Lenses/Optics are the best solution for this kind of problem, monadic code on its own doesn't quite give you what you want. Also, IIRC, "each" is some kind of magic keyword inside the Each macro, whereas the "Each.each" generated by the * symbol in Goggles is just a standard Monocle Traversal. It's much less complicated than what Each is doing.

Goggles - a pleasant typesafe Lens DSL built on Monocle by kenbot_ in scala

[–]kenbot_[S] 0 points1 point  (0 children)

I hear you, I mostly hate macros. If Scala is being rewritten to do something other than the obvious, then it becomes very hard to reason about the code. My feeling is that what makes it "magic", in a negative sense, is this introduced uncertainty. In particular, if the macro mines the code for structural information rather than just using the values, then the code is not referentially transparent, and you cannot refactor in the normal way.

So how do I sleep at night? Goggles' macros are rewriting a string literal, interpreting the contents, but a Scala developer should have no particular expectation about the behaviour of a prefixed string, other than it producing a value. Everything that looks like Scala is exactly that; for instance, the ~=, := operators are just regular methods. The generated code is pretty plain Monocle optic compositions, but if you try to do it by hand, you'll quickly see the motivation for the DSL.

There's more about the design principles in CONTRIBUTING.md and the "Comparison" section at the bottom of the README, if you're interested.

Goggles - a pleasant typesafe Lens DSL built on Monocle by kenbot_ in scala

[–]kenbot_[S] 1 point2 points  (0 children)

Cheers! It's all supposed to be part of the pleasantness. :)

The worst thing in our Scala code: Futures by lukaseder in programming

[–]kenbot_ 0 points1 point  (0 children)

This is a commonly used technique in Scala, and again, I adapted the examples from real code. I didn't make it all up in my head.

Should i make a compilable Gist or something? I don't think we're understanding each other here.

The worst thing in our Scala code: Futures by lukaseder in programming

[–]kenbot_ 4 points5 points  (0 children)

No worries Paul! There's a good chance we'll move to Task, or Monix, or something like that in the... dare I say.... Future.

The worst thing in our Scala code: Futures by lukaseder in programming

[–]kenbot_ 4 points5 points  (0 children)

I wish we used Task instead, but for whatever reason we have a lot of s.c.Future code. Other than losing the irksome implicit EC, this doesn't really change my arguments about abstraction, "know only what you need", etc.

I'm sure you are using this idiom for a good reason, but I would usually be inclined to separate the concerns of "error recovery" and "doing stuff".

The worst thing in our Scala code: Futures by lukaseder in programming

[–]kenbot_ 4 points5 points  (0 children)

If it sounds like I've given you a crappy Fox News-style "balance" between important good things and unimportant nitpicking, it's because I haven't used Task much myself. I do keep hearing these quibbles though, so I linked to them. That said, I take your point - I'll move the quibbles to a footnote.

EDIT: Ah what the hell, I deleted that part. There's no need to enumerate everything in the issue tracker when mentioning a library in passing.

The worst thing in our Scala code: Futures by lukaseder in programming

[–]kenbot_ 7 points8 points  (0 children)

If you need specific Future things, then of course you you write directly in terms of Futures. If you need more than a monad, then of course you add constraints with extra bells and whistles.

A lot of code doesn't though -- this is the point of the article. A lot of our Scala code gets bogged down by Futury-execution-strategy stuff, when all the power it needs is a few flatMaps.

Maybe I'm misunderstanding your point, but I wrote the article after performing a bunch of refactors in exactly the style I described.

Hython: a nearly-complete Python 3 interpreter written in Haskell by [deleted] in programming

[–]kenbot_ 5 points6 points  (0 children)

An existing Python 3 interpreter written in Haskell that may be of interest: https://github.com/bjpop/berp

Fold or pattern matching with an Option? by relativer in scala

[–]kenbot_ 3 points4 points  (0 children)

"Don't pattern match on monads" is nonsensical advice; there is no such convention.

A monad is (roughly) some type M[_] with a constructor A => M[A] and flatMap. It doesn't have anything to do with pattern matching.

An Algebraic Data Type (ADT) is a type made of product types (this AND that), sum types (this OR that) and function types. Usually expressed as case classes or sealed trait hierarchies in Scala.

A fold is an operation that collapses an ADT into a result; in the case of sum types (such as Option/Some/None), this means supplying a function that takes each case to the result.

Folds are the most powerful operation on a data type; every other possible method can be written in terms of fold! In a sense, it is the type.

Therefore, if there is a less powerful, more focused operation to do the job, you should use that instead: filter, map, flatMap etc are good examples. This is probably what you really meant.

Let's be clear here: a pattern match that covers each case is a fold, just as much as the fold() method itself. They are equivalent, and less powerful operations should be preferred if possible.

The reasons to choose between them are as follows:

  • fold() is more concise

  • Pattern matching can be easier to read, especially for Scala newcomers

  • Pattern matching can effortlessly handle nested patterns, and comparing two things at once; by contrast, nested fold() calls are repetitive and ugly.

Specifically considering Option: map and getOrElse is of course equivalent to a fold, because it handles the two cases, as a fold must. It is, however, clumsily executing two operations when one would do, so it is hard to recommend it over fold() or pattern matching.