-
-
Save JoeyEremondi/26de88df1cadbc5347d9 to your computer and use it in GitHub Desktop.
-- interface is a more familiar name for the intention of the construct | |
type alias Append a rest = { rest | append : a -> a -> a} | |
-- implement is a more familiar name | |
stringAppend rest = {rest | append = \x y -> x ++ y} | |
-- this is Monoid | |
type alias AppendWithId a rest = Append a {rest | id : a} | |
-- ^ 1 potential superclass | |
appendWithIdString rest = {rest | id = ""} | |
type alias Eq a rest = | |
{rest | eq : a -> a -> Bool} | |
neq : Eq a rest -> a -> a -> Bool | |
neq inst x y = not <| inst.eq x y | |
concat : AppendWithId a rest -> List a -> a | |
concat inst list = | |
case list of | |
(x::xs) -> | |
inst.append x (concat inst xs) | |
[] -> | |
inst.id | |
foo : Append a rest -> Eq a rest -> a -> a -> a | |
foo ainst einst x y = | |
if neq einst x y then | |
ainst.append x y | |
else | |
x |
I'll take HKP, just so long as there is a way. Since HKP would be nice in more contexts, is a smaller departure, and is a smaller feature, HKP first sounds nice and conservative. Then a more informed estimation is possible, after seeing how dictionary passing works in practice. Is there a way I can lobby for HKP as a feature?
Basically, any lobbying should be rooted in use cases. What, specifically, is not having HKP stopping you from producing in Elm? Or, what negative artifacts / antipatterns are showing up in your code because of it?
Evan definitely won't integrate it just because people think it's a cool feature.
HKP and Typeclasses are completely orthogonal
I never said they weren't. Indeed, with HKP we could make these not-typeclasses records work.
What, specifically, is not having HKP stopping you from producing in Elm?
Something along these lines:
type alias Chainable m rest =
{ rest |
constant : a -> m a,
map : (a -> b) -> m a -> m b,
andMap : m (a -> b) -> m a -> m b,
andThen : (a -> m b) -> m a -> m b
}
sequence : Chainable m rest -> m b -> m a -> m b
sequence {andThen} after before =
andThen (\_ -> after) before
map2 : Chainable m rest -> (a -> b -> c) -> m a -> m b -> m c
map2 {map, andMap} f a b =
map f a `andMap` b
As a reminder, the real benefit of type classes is not generic code. We have most of that already thanks to consistent naming across libraries. The benefit is being able to take a small API and build many more useful things on top of it. For example, anything that can be compared can support min
and max
, and a list of comparable things is sortable.
Is the ability to generalize functions over Monads not a sufficient use case?
Monads for monads' sake don't count for anything. See Joey's comment: what can't you build? How is your code adversely affected? Granted, my example isn't really concrete either.
I guess I feel differently, in that monads for monads sake is useful. One of the appeals of working in a functional languages is the many problems are solved for you by useful functions, and reduce cognitive overhead by using simple polymorphic abstractions. sequence
is a great example, if we had sequence
I would not have to write it myself so frequently and for different types. I can do it because I understand this one very well, but I'd not claim that for all the functions I regularly use, nor would I want to demand that level of understanding from others, simply to take advantage of useful abstractions like sequence
or andMap
.
I guess I feel differently, in that monads for monads sake is useful.
This is a complaint as old as Elm itself. I would recommend reading this post from Evan on this subject, and maybe some surrounding context in that thread.
True, but I stand by my opinion that HKP and Typeclasses are completely orthogonal. That you can add HKP to get that kind of generics without having any special typeclass syntax.