Adding Syntactic Sugar to Make Prismatic Schema Look Like Core.Typed/Haskell - haskell

Consider the way core.typed annotates a function:
(t/ann typed-function [t/Str :-> t/Str])
Now consider the way Prismatic Schema annotates a function:
(s/defn schema-function :- s/Str
[arg :- s/Str]
arg)
Personally, I find the way that core.typed annotates a function be much clearer and closer in spirit to strongly typed languages like Haskell.
Question: Is there a way to make some sort of macro or function in clojure with Prismatic Schema that has the effect of (2) but the visual appearance of (1)? That is, something like the following:'
(custom-annotation-macro schema-function [s/Str :-> s/Str])
(defn schema-function [arg] arg)
such that the effect is merely just
(s/defn schema-function :- s/Str
[arg :- s/Str]
arg)

To illustrate how you could solve this with two macros:
(def type-annots (atom (hash-map)))
(defn add-type-annot [fn-name ty]
(swap! type-annots #(conj % [fn-name ty])))
(defmacro custom-annotation-macro [fn-name ty]
(add-type-annot fn-name ty)
nil)
(defn split-fun-type [ty]
;; You will need to write this one;
;; it should split [a :-> b :-> c] to [[a b] c]
['[s/Str s/Int] 's/Str])
(defmacro defn-typed [fn-name args & body]
(let [ty (get #type-annots fn-name)]
(if ty
(let [[arg-types ret-ty] (split-fun-type ty)
args-typed (apply vector (apply concat (map vector args arg-types)))]
`(s/defn ~fn-name :- ~ret-ty ~args-typed ~#body))
`(defn ~fn-name ~args ~#body))))
I haven't bothered to implement split-fun-type because I don't really know Clojure; the above is based on my understanding that it's a Lisp.

Related

Can `match` in Racket have patterns with variables from an outer scope?

Consider the following example:
#lang racket
(match '(cat . doge)
[`(,a . ,b)
(match b
[a #t]
[_ #f])]
[_ "Not a pair"])
This is what I might write if I wanted to match pairs where the head and tail are the same. This doesn't work though because the second a is bound as a new variable (and matches anything). Are there any pattern forms which allow me to use the previously bound a from the outer scope?
I know this can be achieved in the following way
(match* ('cat 'doge)
[(a a) #t]
[(_ _) #f])
but I still would like to know if there is a way to get that variable from the outer scope (or if there is a reason for not doing so, like some potential name collision problem or something).
Use ==:
(match '(cat . doge)
[`(,a . ,b)
(match b
[(== a) #t]
[_ #f])]
[_ "Not a pair"])
Due to the placement in the docs, == is easy to overlook.

What are the reasons that protocols and multimethods in Clojure are less powerful for polymorphism than typeclasses in Haskell?

More broadly this question is about various approaches to the expression problem. The idea is that your program is a combination of a datatype and operations over it. We want to be able to add new cases without recompiling the old classes.
Now Haskell has some really awesome solutions to the expression problem with the TypeClass. In particular - we can do:
class Eq a where
(==) :: a -> a -> Bool
(/=) :: a -> a -> Bool
member :: (Eq a) => a -> [a] -> Bool
member y [] = False
member y (x:xs) = (x == y) || member y xs
Now in Clojure there are multimethods - so you can do:
(defmulti area :Shape)
(defn rect [wd ht] {:Shape :Rect :wd wd :ht ht})
(defn circle [radius] {:Shape :Circle :radius radius})
(defmethod area :Rect [r]
(* (:wd r) (:ht r)))
(defmethod area :Circle [c]
(* (. Math PI) (* (:radius c) (:radius c))))
(defmethod area :default [x] :oops)
(def r (rect 4 13))
(def c (circle 12))
(area r)
-> 52
(area c)
-> 452.3893421169302
(area {})
-> :oops
Also in Clojure you have protocols - with which you can do:
(defprotocol P
(foo [x])
(bar-me [x] [x y]))
(deftype Foo [a b c]
P
(foo [x] a)
(bar-me [x] b)
(bar-me [x y] (+ c y)))
(bar-me (Foo. 1 2 3) 42)
=> 45
(foo
(let [x 42]
(reify P
(foo [this] 17)
(bar-me [this] x)
(bar-me [this y] x))))
=> 17
Now this individual makes the claim:
But, there are protocols and multi-methods. These are very powerful, but not as powerful as Haskell's typeclasses. You can introduce something like a typeclass by specifying your contract in a protocol. This only dispatches on the first argument, whereas Haskell can dispatch on the entire signature, including return value. Multi-methods are more powerful than protocols, but not as powerful as Haskell's dispatch.
My question is: What are the reasons that protocols and multimethods in Clojure are less powerful for polymorphism than typeclasses in Haskell?
Well the obvious one is that protocols can only dispatch on the first and only the first argument. This means they're roughly equivalent to
class Foo a where
bar :: a -> ...
quux :: a -> ...
...
Where a must be the first argument. Haskell's type classes let a appear anywhere in the function. So protocols are easily less expressive than typeclasses.
Next is multimethods. Multimethods, if I'm not mistaken, allow dispatch based on a function of all the arguments. This looks more expressive in some ways than Haskell, since you can dispatch arguments of the same type differently. However, this can actually be done in Haskell, generally by wrapping the argument in a newtype for dispatching.
A few things that can't be done with multimethods to my knowledge:
Dispatch on return type
Store values polymorphic over all types of a type class forall a. Foo a => a
To see how 1. comes into play, consider Monoid it has a value mempty :: Monoid m => m. It's not a function, and simulating this is impossible with Clojure since we don't have any type information about what method we're expected to choose.
For 2. consider read :: Read a => String -> a. In Haskell we could actually create a list which has the type [forall a. Read a => a], we've essentially deferred the computation and we can now run and rerun elements of the list to attempt to read them as different values.
Typeclasses also have static types so there's some checking to make sure you're not going to end up "stuck" without an instance to call statically, but Clojure is dynamically typed so I'll chalk this up to a difference in style between the two languages rather than a particular advantage one way or the other. Also of course is the advantage that typeclasses have a lot less overhead than multimethods since generally the witness record can be inlined and everything is resolved statically.
The most fundamental difference is that with type classes, dispatch is on types not on values. No value is needed to perform it. That allows much more general cases. The most obvious example is dispatch on (part of) the result type of a function. Consider e.g. Haskell's Read class:
class Read a where
readsPrec :: Int -> String -> [(a, String)]
...
Such dispatch is clearly impossible with multi-methods, which have to dispatch on their arguments.
See also my more extensive comparison with plain OO.

What is the clojure equivalent for Haskell's <-?

I'm trying to figure out the IO monad and the <- syntax which I often see in Haskell code. I've seen it used with multiple datatypes, including arrays and IO.
What is the equivalent operation in clojure if I were to specify one myself?
Do-notation is just sugar for the standard monad operations. For example, if you have something like this:
do
x <- someMonad
return (someFunction x)
That's equivalent to this:
someMonad >>= \x -> return (someFunction x)
So the equivalent Clojure using one of the many monad libraries might be something like this:
(m-bind some-monad (fn [x] (m-result (some-function x))))
Using algo.monads, we can define an IO monad easily (if unnecesarrily).
In Haskell, the IO monad is type IO a = World -> (a, World). It's handy to think of this as an action - something which takes the world, does something, and returns a value and the world.
Using a vector instead of a tuple, this means that, in Clojure, an IO action (a monadic value of the IO monad) looks something like this:
(fn [world]
; some stuff
[value world])
To do something interesting, we need a couple of actions: get-char and put-char.
get-char is an action which takes in the world, reads a char, and returns that char as its value alongside the world:
(defn read-char
[]
(-> *in* .read char))
(defn get-char
[world]
[(read-char) world])
put-char takes a character and creates an action which, given a world, prints the character and returns some (inconsequential) value:
(defn put-char
[c]
(fn [world]
(print c)
[nil world]))
Note that, to make an action happen, we have to supply a world. For instance, (put-char \a) will return an action; ((put-char \a) :world) will invoke that action, printing a and returning [nil :world].
Composing these actions is potentially a very messy process. If, for example, you wanted to get a character, then print it, you'd have to call get-char, unpack its character and world, create an action for that character with put-char, then pass the world to that action.
On the other hand, if we define a monad, we get domonad (the equivalent to Haskell's do) for free. This syntactic sugar alleviates the unpacking/packing boilerplate. We just need a few functions: m-result and m-bind (m-zero and m-plus are also handy, but not necessary).
m-result (return in Haskell) takes a value and wraps it up as an action:
(fn [v]
(fn [world]
[v world]))
m-bind (>>= in Haskell) takes an action and a function which takes a regular value to produce an action, "unwraps" the value by invoking the action, and applies the function to it. With the IO monad, that looks like this:
(fn [io f]
(fn [world]
(let [[v new-world] (io world)]
((f v) new-world))))
So, using algo.monads, we can define io-m as follows:
(defmonad io-m
[m-result (fn [v]
(fn [world]
[v world]))
m-bind (fn [io f]
(fn [world]
(let [[v new-world] (io world)]
((f v) new-world))))])
Now that we've got the primitive IO actions and a means of composing them, we can create more interesting ones. Note that Haskell's unpacking operator (<-) is implicit and the result is automatically wrapped with m-result so we don't use Haskell's return statement to terminate the expressions:
(declare get-rest-of-line)
(def get-line
(domonad io-m
[c get-char
line (if (= c \newline)
(m-result "")
(get-rest-of-line c))]
line))
(defn get-rest-of-line
[c]
(domonad io-m
[cs get-line]
(str c cs)))
(defn put-line
[s]
(if (seq s)
(domonad io-m
[_ (put-char (first s))
_ (put-line (subs s 1))]
_)
(put-char \newline)))
Finally, we can write a program in terms of these IO actions:
(def run-program
(domonad io-m
[line get-line
:let [reversed-line (->> line reverse (apply str))]
_ (put-line reversed-line)]
_))
(run-program :world)
I think Chuck has answered your main question, but in case you'd like to investigate the way the monad operations can be implemented in Clojure using algo.monads as an example, the following:
(domonad state-m
[_ (set-state "foo")
x (fetch-state)]
x)
is equivalent (well, almost, see below) to Haskell's
do
_ <- put "foo" -- see below for a comment on this
x <- get
return x
In algo.monads the <- disappears, because effectively it is implied on every line.
About the "almost" and the _ above: _ actually isn't magic in Clojure and it will be bound to the value returned by set-state, but it's idiomatic to use this symbol as the name of locals one doesn't care about. Of course in Haskell it would be more usual simply to write put "foo" instead of _ <- put "foo".

Continuation passing style - function composition

I'm learning about CPS with Racket, and I've managed to write up these functions:
;lift a regular single-arg function into CPS
(define (lift/k f)
(lambda (x k)
(k (f x))))
;compose two CPS functions
(define (compose/k f g)
(lambda (x k)
(g x (lambda (y)
(f y k)))))
They seem to work correctly
(define (is-two/k x k)
(k (= x 2)))
(define is-not-two/k (compose/k (lift/k not) is-two/k))
(is-not-two/k 3 display)
(is-not-two/k 2 display)
#t#f
I'm wondering if these functions are still "true CPS". Have I messed up "true" continuation-passing with these functions? Is it kosher to use function composition techniques in CPS? Is it encouraged? Or would it be considered a "compromise" to do this? Is there a more CPS-y way to do it?
Yes I know I just asked 5 questions, but the basic idea behind them all (which I'm not sure I understand correctly) is the same. Explanations in other Lisps, Haskell, Erlang, or other functional languages are fine.
The continuation-passing-style transform can be partial, or complete. You're usually working with a system where certain primitives (+, -, etc.) are stuck in non-cps-land. Fortunately, CPS works fine either way.
The steps in CPSing:
Pick which functions are going to be primitive.
CPS-transform so that all non-primitive functions (including continuations) are called only in tail position.
So, in your code, your 'lift/k' is essentially treating its given function as being primitive: note that the body of lift/k calls 'f' in non-tail position. If you want not to treat the lifted function as a primitive, you must go in and rewrite it explicitly.
Your 'compose' function composes two CPSed functions, but is not itself in CPS (that is, you're assuming that 'compose' is primitive. You probably want to CPS it. Note that since it just returns a value straight off, this is simple:
;compose two CPS functions
(define (compose/k f g k)
(k (lambda (x k)
(g x (lambda (y)
(f y k))))))

Practical use of curried functions?

There are tons of tutorials on how to curry functions, and as many questions here at stackoverflow. However, after reading The Little Schemer, several books, tutorials, blog posts, and stackoverflow threads I still don't know the answer to the simple question: "What's the point of currying?" I do understand how to curry a function, just not the "why?" behind it.
Could someone please explain to me the practical uses of curried functions (outside of languages that only allow one argument per function, where the necessity of using currying is of course quite evident.)
edit: Taking into account some examples from TLS, what's the benefit of
(define (action kind)
(lambda (a b)
(kind a b)))
as opposed to
(define (action kind a b)
(kind a b))
I can only see more code and no added flexibility...
One effective use of curried functions is decreasing of amount of code.
Consider three functions, two of which are almost identical:
(define (add a b)
(action + a b))
(define (mul a b)
(action * a b))
(define (action kind a b)
(kind a b))
If your code invokes add, it in turn calls action with kind +. The same with mul.
You defined these functions like you would do in many imperative popular languages available (some of them have been including lambdas, currying and other features usually found in functional world, because all of it is terribly handy).
All add and sum do, is wrapping the call to action with the appropriate kind. Now, consider curried definitions of these functions:
(define add-curried
((curry action) +))
(define mul-curried
((curry action) *))
They've become considerable shorter. We just curried the function action by passing it only one argument, the kind, and got the curried function which accepts the rest two arguments.
This approach allows you to write less code, with high level of maintainability.
Just imagine that function action would immediately be rewritten to accept 3 more arguments. Without currying you would have to rewrite your implementations of add and mul:
(define (action kind a b c d e)
(kind a b c d e))
(define (add a b c d e)
(action + a b c d e))
(define (mul a b c d e)
(action * a b c d e))
But currying saved you from that nasty and error-prone work; you don't have to rewrite even a symbol in the functions add-curried and mul-curried at all, because the calling function would provide the necessary amount of arguments passed to action.
They can make code easier to read. Consider the following two Haskell snippets:
lengths :: [[a]] -> [Int]
lengths xs = map length xs
lengths' :: [[a]] -> [Int]
lengths' = map length
Why give a name to a variable you're not going to use?
Curried functions also help in situations like this:
doubleAndSum ys = map (\xs -> sum (map (*2) xs) ys
doubleAndSum' = map (sum . map (*2))
Removing those extra variables makes the code easier to read and there's no need for you to mentally keep clear what xs is and what ys is.
HTH.
You can see currying as a specialization. Pick some defaults and leave the user (maybe yourself) with a specialized, more expressive, function.
I think that currying is a traditional way to handle general n-ary functions provided that the only ones you can define are unary.
For example, in lambda calculus (from which functional programming languages stem), there are only one-variable abstractions (which translates to unary functions in FPLs). Regarding lambda calculus, I think it's easier to prove things about such a formalism since you don't actually need to handle the case of n-ary functions (since you can represent any n-ary function with a number of unary ones through currying).
(Others have already covered some of the practical implications of this decision so I'll stop here.)
Using all :: (a -> Bool) -> [a] -> Bool with a curried predicate.
all (`elem` [1,2,3]) [0,3,4,5]
Haskell infix operators can be curried on either side, so you can easily curry the needle or the container side of the elem function (is-element-of).
We cannot directly compose functions that takes multiple parameters. Since function composition is one of the key concept in functional programming. By using Currying technique we can compose functions that takes multiple parameters.
I would like to add example to #Francesco answer.
So you don't have to increase boilerplate with a little lambda.
It is very easy to create closures. From time to time i use SRFI-26. It is really cute.
In and of itself currying is syntactic sugar. Syntactic sugar is all about what you want to make easy. C for example wants to make instructions that are "cheap" in assembly language like incrementing, easy and so they have syntactic sugar for incrementation, the ++ notation.
t = x + y
x = x + 1
is replaced by t = x++ + y
Functional languages could just as easily have stuff like.
f(x,y,z) = abc
g(r,s)(z) = f(r,s,z).
h(r)(s)(z) = f(r,s,z)
but instead its all automatic. And that allows for a g bound by a particular r0, s0 (i.e. specific values) to be passed as a one variable function.
Take for example perl's sort function which takes
sort sub list
where sub is a function of two variables that evaluates to a boolean and
list is an arbitrary list.
You would naturally want to use comparison operators (<=>) in Perl and have
sortordinal = sort (<=>)
where sortordinal works on lists. To do this you would sort to be a curried function.
And in fact
sort of a list is defined in precisely this way in Perl.
In short: currying is sugar to make first class functions more natural.

Resources