Open tonyhffong opened 9 years ago
I have tried a few time but never understood monads... Anyway, there might be progress on accessing type parameters coming: https://github.com/JuliaLang/julia/issues/8974#issuecomment-68648607
Note that at the moment you can get at the type parameters using associated types:
tpar1(t::Type) = t.parameters[1]
@traitdef Indexable{X} begin
Y = tpar1(X)
getindex(X, Any) -> Y
setindex!(X, Y, Any) -> X
end
However, that would require that all indexable types have their element type as first parameter, so maybe better:
@traitdef Indexable{X} begin
Y = eltype(X)
getindex(X, Any) -> Y
setindex!(X, Y, Any) -> X
end
It would be cool if you could piece together a monad example using Traits, please submit a pull request!
(I also edited @tonyhffong's original post to make the citing clearer)
Interesting. I definitely want to play with it some more. Conceptually, though, a monad always need a type parameter, so ideally we should do something like this:
@traitdef Monad{X{Y}} begin
mreturn(Y) -> X{Y}
bind( X{Y}, FuncFullSig{ Y, X{Z} } ) -> X{Z}
end
Assuming we have for FuncFullSig
:
immutable FuncFullSig{TI,TO} # a function that is f(x::TI)::TO
f::Function
end
As you can see, mreturn
's call signature is a bit funky already. Directly it doesn't reference X at all.
Let's take Nullable
as a hypothetical case. So we need to define somehow:
mreturn{T;Monad{Nullable{T}}}(x::T) = Nullable{T}(x)
function bind{T;Monad{Nullable{T}}}(x::Nullable{T}, f::FuncFullSig{T,Nullable{Z}} )
if isnull(x)
return Nullable{Z}()
else
return f.f( x.value ) # ideally, we could have a try block here too.
end
end
We can chain all nullable functions even if their arguments do not understand Nullable.
Disclaimer: I'm struggling with how the dispatch should really work in this case. So all these are hypothetical.
For completeness, I've also come across an experimental package https://github.com/pao/Monads.jl from @pao.
Regarding monads: I find the bind
function, while convenient for Haskell's >>=
syntax, more difficult to understand than the following basically equivalent definition of a monad:
@traitdef Monad{M{T}} begin
munit(T) -> M{T}
fmap(F, M{T}) -> M{U}
mjoin(M{M{T}}) -> M{T}
end
where fmap
is identical to Base.map
. Its first argument f::F
should have the type T -> U
, but I don't know how to express this in Julia or in Traits.jl. Maybe writing simply M
as return type of fmap
would suffice, since a monad is something like a fancy container, and you have e.g. Array{Int} <: Array
.
I'm intrigued by this statement under
to ponder
which is one of the requirements to define a monad.
What do you think are the challenges in trying to do this?
One can think of Nullable{T}, Array{T}, and many others in terms of monads so the possibilities are quite exciting.