Join the Division discord , find a HVT group , you ' ll be geared in notime <| sep |> Intentionally , yes . In all of the examples you ' ve given , doing so is a better design . Having to use Future for all cases when you only want it for one is not better design . Not being able to newtype things that have to be run in a particular context is not better design . And you ' re changing your argument what I initially said was if code needs to do something more specific than what it can do with monad , it probably needs to simply be concrete rather than generic , and you seem to agree with that much , since all your examples have been replacing generic with concrete . By pushing the logger through the parallelizer . If the logger is not mutable eg . is the null logger , or is in a mutex you can use a parallelization argument that gives a copy to each function . If the logger is mutable , that won ' t type check . I don ' t want it to just not typecheck I want it to serialize when the type implies that ' s necessary and parallelize when the type implies that ' s safe . The type is perfectly capable of specifying this for itself . This is the internal vs external iterator argument from the other side . I don ' t want to have to pass down a logger that can accept logs which seems to be the solution you ' re suggesting rather I want to return my log up . Without compiletime function execution , your parser is going to be type directed . I shouldn ' t have to write a custom parser , the language should give me good support for a literal for expressing a value . Format strings really aren ' t a special case LiteralHello Placeholder HNil is a value I ' d like a nice concise syntax for , but that ' s not qualitatively different from wanting a nice concise syntax for UseraccessADMIN , usernamem 50 d . By that point you ' ve already lost you can no longer make it do anything interesting because type level programming sucks and the errors will be no less horrific because type level errors suck . If they suck , make them better . But I ' m not sure what programming you even have to do . All the interesting properties of a format string like Foo % s , Bar % i are captured by representing it as a FormatStringString Int HNil . Then it ' s trivial to write printlnformat FormatString , parameters F as a normal function . Yes , in Scala I would have to take an implicit parameter coming out of a macro because the language has distinct types for Function 1 to Function 22 and Tuple 1 to Tuple 22 and needs a hack to abstract over them . But the lesson from that is to not do that in your language . Syntax is the only path to semantics macros cannot exist without a syntax to resolve to . Sure , but you can remove as much syntax as possible that ' s what the lisp tradition does you have a syntax for writing raw ASTs directly , any other syntax you ' re expected to implement yourself via macros . It ' s a defensible strategy lisps are alive and wellish but it ' s not the route Rust has gone down , I think rightly . Userdefined derives don ' t make tooling less able to work with builtin derives , nor does tooling having special logic for standard derives somehow compromise user defined ones . The whole point of expressing as much as possible as ordinary functions in ordinary libraries is lost if what look like ordinary functions actually has dedicated tool support . There ' s lessthanzero value in the user being able to read the implementation of a given construct if this doesn ' t actually let them copy and tweak that construct in the way they ' d expect . If deriving needs dedicated support in tools then it is an opaque and inextensible language construct , and it should look like one , rather than pretending to be transparent and extensible when it isn ' t . Macros are a compiletime construct . You pass macros to higher order macros . Which makes sense they resolve at compiletime , so passing them around at runtime is more than a bit silly . Sure , so they ' re secondclass . That ' s probably not entirely avoidable , but the more you can move into firstclass code the better . Under what I ' m proposing the format literals would still be secondclass to a certain extent all literals are secondclass most languages don ' t offer you a way to take a runtime string and interpret it as if it were a literal in the language source , but the println part could be an ordinary firstclass function . Rust requires macros to have an exclamation mark precisely so that they ' re always visible . Which is an improvement over many languages . But at a higher level , I expect to be able to run the compiler on a directory full of source files and have it compile them into output , without having to read all the source files to know whether it ' s going to connect to a database access the internet read my local C headers read some config file from another directory . Again , I don ' t know the specifics of what bindgen does . I ' m not sure what ' s up with Scala , though after you pushing it as the solution so hard I ' m a bit dazzled the internet seems to be telling me it has no Resultlike monad . You use orXor depending on your politics , or from 2 . 12 onward you use standardlibrary Either . Scala is terrible at naming things and terrible at community politics which are some of the reasons I ' d very much like for Rust to be a viable alternative . Another major difficulty is point # 1 using FnOnce instead of Fn . The general monad abstraction would have to use Fn , and although the later is an instance of the former , this means that Result is strictly less powerful when used through the monadic abstraction . When I use andthen on a nonmonadic Result , I can provide a lambda that is only callable once . When I use it on a monadic Result , I cannot . This is primarily what I mean by the abstraction fighting you it forces you to do all sorts of things to your code that are entirely irrelevant to the logic you want to express . Heh , this is exactly my issue with you telling me just to pass a generic parameter through to child code without being able to distinguish between whether it ' s readonly , appendonly or readwrite . And in the same way , it seems trivial to solve using HKT , something like trait MonadForF , FnTypeA , O def flatMapA , Bfa F , fab FnTypeA , F . Then you ' d have implementations of MonadForResult ? , E , FnOnce type Output ? which is valid for FnMut and Fn since they ' re subtypes of FnOnce and of MonadForNondeterminism , Fn type Output ? if your highlevel code needs to pass FnOnces it can take a MonadForF , FnOnce so it will be callable with FResult but not with FNondeterminism , if it only needs to pass Fns it can take a MonadForF , Fn and it will be callable with either . There shouldn ' t be a dynamicdispatch issue since I would assume the differences between subtypes of FnOnce are erased at runtime and the compiler knows this . This is ignoring the fact that the nonmonadic andthen is already fighting you , which is why try ! even exists in the first place ! I don ' t know why try ! doesn ' t desugar to andthen , but it certainly looks to do the equivalent thing . I ' d support a try ! equivalent that used andthen so that it worked with Future and other monads I just think it should ultimately be promoted to a language feature rather than a macro .