This repository was archived by the owner on Feb 7, 2019. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 6
[WIP] first stab at parametrically-typed trait (e.g. monad) #4
Closed
Closed
Changes from all commits
Commits
Show all changes
13 commits
Select commit
Hold shift + click to select a range
9806452
first stab at parametrically-typed trait (e.g. monad)
tonyhffong 47beb44
make traitimpl aware of associated type
tonyhffong e1211c3
Add parametric trait tests. mod some test due to..
tonyhffong e974821
remove my own dead code
tonyhffong 79c78f8
remove non-existent function in export
tonyhffong 8febf07
a "better" trait match scoring scheme
tonyhffong 426352f
cache trait singleton
tonyhffong 6918865
better tests and examples
tonyhffong 576dd45
"fixed" previous ambiguities
tonyhffong c617cdd
fix distracting error in examples
tonyhffong d921050
bugfix multi-parameter-parametric trait
tonyhffong 167d4ab
Merge remote-tracking branch 'upstream/master' into tf/monads
tonyhffong fa5c0b4
revert dispatch scoring mechanism to status quo
tonyhffong File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -97,6 +97,12 @@ end | |
Z = promote_type(X,Y) # calculates Z from X and Y | ||
fun5(X,Y) -> Z | ||
end | ||
|
||
# using parametric trait. Note the nested curly | ||
@traitdef SemiFunctor{X{Y}} begin | ||
fmap( Function, X{Y} } -> Any | ||
end | ||
|
||
``` | ||
Note that return-type checking is quite experimental. It can be | ||
turned off by defining `Main.Traits_check_return_types=false` before | ||
|
@@ -155,6 +161,17 @@ try | |
catch e | ||
println(e) # ErrorException("assertion failed: istrait(Tr4{Int,Float64})") | ||
end | ||
|
||
# for parametric trait, | ||
@traitimpl SemiFunctor{Nullable{T}} begin | ||
fmap{T}( f::Function, x::Nullable{T}) = isnull(x) ? Nullable() : Nullable(f(x.value)) | ||
end | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This implementation of
Is that intended? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No it's not. I'll fix. |
||
|
||
# for Array, it is a bit difficult because the eltype is the first argument. | ||
# Also note that this sample implementation won’t cover higher dimensions | ||
@traitimpl SemiFunctor{Array{T...}} begin | ||
fmap{T}( f::Function, x::Array{T,1}) = map(f, x) | ||
end | ||
``` | ||
|
||
Trait functions & dispatch: | ||
|
@@ -342,16 +359,9 @@ do not have a strict hierarchy like types. | |
|
||
- Are there better ways for trait-dispatch? | ||
|
||
- Sometimes it would be good to get at type parameters, for instance | ||
for Arrays and the like: | ||
```julia | ||
@traitdef Indexable{X{Y}} begin | ||
getindex(X, Any) -> Y | ||
setindex!(X, Y, Any) -> X | ||
end | ||
``` | ||
This problem is similar to triangular dispatch and may be solved | ||
by: https://github.com/JuliaLang/julia/issues/6984#issuecomment-49751358 | ||
- Issues related to parametric trait: | ||
* Triangular dispatch: | ||
https://github.com/JuliaLang/julia/issues/6984#issuecomment-49751358 | ||
|
||
# Issues | ||
|
||
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,131 @@ | ||
using Traits | ||
|
||
immutable FuncFullSig{TI, TO} | ||
f::Function | ||
end | ||
|
||
call{TI,TO}( fs::FuncFullSig{TI,TO}, x::TI ) = (fs.f(x))::TO | ||
|
||
# I use the prefix "Semi" to remind ourselves that the | ||
# there may not be a guarantee of function output type | ||
@traitdef SemiFunctor{X{Y}} begin | ||
fmap( Function, X{Y} ) -> Any | ||
end | ||
|
||
@traitdef Functor{X{Y}} begin | ||
fmap( FuncFullSig{Y,Z}, X{Y} ) -> X{Z} | ||
end | ||
|
||
@traitdef SemiMonad{X{Y}} begin | ||
mreturn( ::X,Y) ->X{Y} | ||
bind( Function, X{Y} ) -> Any | ||
end | ||
|
||
# ::X is the shorthand for singleton type argument | ||
@traitdef Monad{X{Y}} begin | ||
mreturn(::X, Y) -> X{Y} # we cannot infer X so we have to supply it | ||
bind( FuncFullSig{Y, X{Y}}, X{Y} ) -> X{Y} | ||
end | ||
|
||
# === implementation of traits | ||
@traitimpl SemiMonad{ Nullable{Y} } begin | ||
mreturn{Y}( ::Type{Nullable}, x::Y ) = Nullable{Y}(x) | ||
bind{Y}( f::Function, x::Nullable{Y} ) = begin | ||
if isnull(x) | ||
return Nullable() | ||
else | ||
try | ||
return f( x.value ) | ||
catch | ||
return Nullable() | ||
end | ||
end | ||
end | ||
end | ||
|
||
@traitimpl SemiMonad{ Array{Y...} } begin | ||
mreturn{Y}( ::Type{Array}, x::Y ) = Y[x] | ||
bind{Y}( f::Function, x::Array{Y,1} ) = [ f(_) for _ in x ] | ||
end | ||
|
||
# === some combo traits ====== | ||
@traitdef MonadRelated1{ X{Y}, Z } <: SemiMonad{X} begin | ||
@constraints begin | ||
Y == Z | ||
end | ||
end | ||
|
||
@traitimpl SemiFunctor{ Array{Y...} } begin | ||
fmap{Y}( f::Function, x::Array{Y,1} ) = map(f, x) | ||
end | ||
|
||
# the deparameterize_type is ugly, but at least we don't have | ||
# to do it many times | ||
@traitfn mequal{M,Y;MonadRelated1{M,Y}}( x::M, y::Y ) = | ||
isequal( x, mreturn( Traits.deparameterize_type(M), y ) ) | ||
|
||
@traitfn mequal{Y,M;MonadRelated1{M,Y}}( x::Y, y::M ) = | ||
isequal( y, mreturn( Traits.deparameterize_type(M), x ) ) | ||
|
||
mequal( x, y ) = isequal( x, y ) | ||
|
||
@assert mequal( Nullable( 1.0 ), 1.0 ) | ||
@assert mequal( 1.0, Nullable( 1.0 ) ) | ||
|
||
# but it's better than that. Since we have Array being a SemiMonad, | ||
# we get this for free | ||
@assert mequal( 1.0, [ 1.0 ] ) | ||
@assert mequal( [1.0], 1.0 ) | ||
|
||
# now we compare an Array of nullables and a simple Array | ||
@traitdef CollectionM{X{Y}} <: Collection{X} begin | ||
@constraints begin | ||
istrait( SemiMonad{Y} ) # we cannot put it in the header | ||
end | ||
end | ||
@traitdef IterM{X{Y}} <: Iter{X} begin | ||
@constraints begin | ||
istrait( SemiMonad{Y} ) # we cannot put it in the header | ||
end | ||
end | ||
|
||
@traitdef SemiFunctorMonad{X{Y}} <: SemiFunctor{X} begin | ||
@constraints begin | ||
istrait( SemiMonad{Y} ) | ||
end | ||
end | ||
|
||
@traitfn mequal(X,Y;CollectionM{X}, Collection{Y})( xc::X, yc::Y ) = begin | ||
println( "using CollectionM comparison") | ||
if length(xc) != length(yc) | ||
return false | ||
end | ||
xs = start(xc) | ||
ys = start(yc) | ||
while( !done(xc, xs) ) | ||
x,xs = next(xc,xs) | ||
y,ys = next(yc,ys) | ||
if !mequal( x, y ) | ||
return false | ||
end | ||
end | ||
return true | ||
end | ||
@traitfn mequal(X,Y;IterM{X}, Iter{Y})( xc::X, yc::Y ) = begin | ||
println( "using IterM comparison") | ||
xs = start(xc) | ||
ys = start(yc) | ||
while( !done(xc, xs) && !done( yc, ys) ) | ||
x,xs = next(xc,xs) | ||
y,ys = next(yc,ys) | ||
if !mequal( x, y ) | ||
return false | ||
end | ||
end | ||
if !done(xc,xs) || !done(yc,ys) | ||
return false | ||
end | ||
return true | ||
end | ||
|
||
@assert mequal( [ Nullable(1.0), Nullable(2.0) ], [1.0, 2.0 ] ) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could the return type not be more specific here? Otherwise there seems to be no need have a parametric type if none of the parameters actually feature.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes I thought about that, but for staging to work, I think we would need access to the input/output type of functions during the staging phase. Here's a recent comment I made on this topic: JuliaLang/julia#7474 (comment)