Am Di., 9. Juni 2020 um 19:13 Uhr schrieb Adam Nelson <xxxxxx@nels.onl>: > > (What do you mean by "difficult to use in a dynamically-typed > > language"? That is an orthogonal concept, isn't it?) > Yes, this was more of a concern about SRFI 165 and similar attempts to > bring monads into dynamically-typed languages, which usually result in > code that is difficult to follow because of the lack of type > annotations. It probably wasn't relevant to bring into this conversation. The lack of type annotations is again orthogonal to the concept of monads, I'd say. (Moreover, I'd add that you cannot really "bring" monads into a language. They are always there as soon as some patterns appear.) When code is difficult to follow "because of the lack of type annotations", this is mainly a problem of documentation. Even in Haskell, code can become hard to follow when type annotations are not given but to be inferred by the HM system. Dynamically-typed languages even have some advantages due to their flexibility. A static type system like, say, Haskell's just cannot express any type one can think of. So at some point, one may need explaining in words anyway. But see SRFI 41 for a specification that uses type annotations to document Scheme code. The higher-order procedure of SRFI 1 could also be nicely (partly) documented through type annotations. Note that this and the previous example has nothing to do with monads (at least not obviously as lists and promises and streams each form monads, of course). > > Longer yes; the `let*' may or may not be more confusing (depending on > > whether you know `and-let*' or not); but the explicit use of `cut' > > would definitely make it more, err, explicit and, thus, easier to > > understand. > True, but it changes the tipping point at which `->` expressions become > easier to read than equivalent plain expressions. Using the `cut` > approach on chains of 3 or fewer calls doesn't accomplish much beyond > adding noise. > > (let* ((<- xs) > > (<- (map (lambda (x) (+ x 1)) <-) > > (<- (filter odd? <-) > > (<- (fold * 1 <-)) > > <-) > This is an interesting expression, and it does kind of communicate that > chaining is taking place. It also establishes a good baseline: threading > macros should be at least terser than this kind of `let*` expression, or > else they serve no purpose. I agree that unifying `let*` and `and-let*` > syntax would be helpful, but that should be a different SRFI, and > probably should not include the `cut` syntax. Would you want to create such a SRFI as well? > > And the fact, that `->' maps in syntax and semantics so easily to > > `let*' lets us explain `->' in Scheme terms. > I should consider using this as a way of explaining these macros in my > next draft. You could use `let*-values' as the base for an mv version of your threading construct. `let*-values' is in the core and should be handled efficiently by implementations, so every syntax/semantics you can reduce to it easily should be efficient.