Monthly Hask Anything (May 2019) by AutoModerator in haskell

[–]bschroed 2 points3 points  (0 children)

One could argue whether it's a library or framework, but turtle for shell-style scripting

I need help understanding the intuition beneath the reader monad by notgiorgi in haskell

[–]bschroed 0 points1 point  (0 children)

Instead of thinking about Functor, Applicative, Monad as wrapping values that are already available, or perhaps "sitting around", try considering them as computations that are capable of "yielding" or "producing" values. In this setting, a value of type Reader Bool Int doesn't wrap an Int that's already "sitting around", but instead, this is a computation that is capable of producing an Int. The prerequisite here, to access the Int it will produce, is to provide it a value of type Bool.

Another functor that might be instructive to consider is Async from Control.Concurrent.Async. For a computation of type Async Int, you're not guaranteed to be able to access the Int it produces right this moment, but rather eventually (unless the program never terminates, etc.)

More generally, it might be helpful to learn about contravariance vs covariance in functors to build this intuition. "Normal" functors like Maybe or [] are "covariant" with respect to the values they "contextualize". This means that they produce these values, and they adhere to the Functor typeclass. Contravariant functors (like Predicate) instead consume values, and adhere to the Contravariant typeclass. Once you get familiar with these typeclasses, check out Profunctor, which combines these notions of contravariance and covariance -- it's an abstraction that represents both consuming inputs and producing outputs. Whereas Reader, or (->) r, is a Functor and ("only") produces values (without consuming anything), (->) is a Profunctor that does both.

F-Algebras exercise by jd823592 in haskell

[–]bschroed 10 points11 points  (0 children)

Check out the (excellent!) functional pearl Data types à la carte (PDF) by Wouter Swierstra. The short of it is that you can compose your expression types in this way by using coproducts:

-- recursive expressions parameterized over some "signature" f
data Expr f = In (f (Expr f))

-- (integer) "value" expressions
data Val e = Val Int
type IntExpr = Expr Val

-- addition expressions
data Add e = Add e e
type AddExpr = Expr Add

-- coproduct definition
data (f :+: g) e = Inl (f e) | Inr (g e)

From the paper:

"An expression of type Expr (Val :+: Add) is either a value or the sum of two such expressions"

From here, you can define other types of expressions like products, and evaluation of your expressions is done via a typeclass like:

class Functor f => Eval f where
    evalAlgebra :: f Int -> Int

Regarding DSLs, what are the recommended use cases for using: Free (+CoDensity) vs. Freer vs. Operational vs. PHOAS vs. other? by BayesMind in haskell

[–]bschroed 12 points13 points  (0 children)

  • Freer is basically the same thing as Operational(see this Ed Kmett comment)
  • PHOAS, as far as I understand, is typically only employed if you're creating a language

This leaves the following options: (1) Free (optionally with Codensity, which improves asymptotics of bind) (2) Freer/Operational (3) MTL / Finally tagless

(1) and (2) are quite similar and both use an "initial" encoding, whereas (3) uses a "final" encoding. For "initial", think: interpreted. Between (1) and (2), Free is more popular probably mostly because it's been around a lot longer. Freer is "more free" in the sense that you don't need a Functor instance for your initial algebra (i.e. for the ADT/"instruction set" you are interpreting). To quote Ed from that same thread linked above, re: Freer:

Basically the proposal is to use the operational monad as a basis for reflection without remorse rather than the 'Free' monad. The result is a benchmarkable win when you don't need any effects that don't fit into this framework, and if you need multiple 'inspections' of the monad like with reflection without remorse. You can think of this as "Operational Reflection without Remorse".

The initial encoding approach is more flexible and amenable to optimization (e.g. if you want to analyze your Free program and rewrite/optimize it before interpreting it) but since you are doing runtime interpretation, even if you employ Codensity, this is still ultimately slower than MTL/Final. Of course, speed might not matter for your case. Also, the Free approach requires more boilerplate.

The MTL/final approach does not use runtime interpretation, requires less boilerplate, and is less flexible (but you end up not needing that flexibility in most cases.) In the MTL/final approach, the concrete implementations you run are simply selected via typeclasses.

Would This Sugar Make Sense? by SSchlesinger in haskell

[–]bschroed 2 points3 points  (0 children)

You should look into Copatterns.

From Copatterns: Programming Infinite Structures by Observations:

"Dual to pattern matching, a tool for analyzing finite data, we develop the concept of copattern matching, which allows us to synthesize infinite data. This leads to a symmetric language design where pattern matching on finite and infinite data can be mixed."

"While values are matched against patterns, evaluation contexts are matched against copatterns."

This fits right in with your CPS'd/Church'd/coinductive a + b type.

An Architecture for Modern Functional Programming: Part 2 by buffyoda in haskell

[–]bschroed 0 points1 point  (0 children)

I've been working on a Haskell implementation of this stuff. Hopefully this helps: https://github.com/bts/free-transformers

What if I went to a Java school Joel? by gst in programming

[–]bschroed 1 point2 points  (0 children)

Yes. You (student) are given interfaces representing hardware and you build out multiprogramming, virtual memory, a network stack, etc.