Here's a full REPL session. where inference seems to break, but maybe I'm missing something with globals and softscope.
julia> using ExtensibleEffects
julia> using TypeClasses
julia> using Test
julia>
julia> vector_of_eff_of_vector = map(x -> noeffect([x]), [1, 20])
2-element Vector{ExtensibleEffects.Eff{NoEffect{Vector{Int64}}, Tuple{}}}:
Eff(effectful=NoEffect{Vector{Int64}}([1]), length(cont)=0)
Eff(effectful=NoEffect{Vector{Int64}}([20]), length(cont)=0)
julia> e1 = vector_of_eff_of_vector[1]
Eff(effectful=NoEffect{Vector{Int64}}([1]), length(cont)=0)
julia> e2 = vector_of_eff_of_vector[2]
Eff(effectful=NoEffect{Vector{Int64}}([20]), length(cont)=0)
julia> function prepare_test(e1, e2)
combine(v1, v2) = [v1; v2]
curried_combine(v1) = v2 -> combine(v1, v2)
e1_f = map(curried_combine, e1)
f_flatmap(f) = TypeClasses.map(v2 -> f(v2), e2)
f_flatmap, e1_f
end
prepare_test (generic function with 1 method)
julia>
julia> f_flatmap, e1_f = prepare_test(e1, e2)
(f_flatmap, Eff(effectful=NoEffect{var"#3#7"{Vector{Int64}, var"#combine#5"}}(var"#3#7"{Vector{Int64}, var"#combine#5"}([1], var"#combine#5"())), length(cont)=0))
julia> @inferred TypeClasses.flatmap(f_flatmap, e1_f) # infers perfectly
Eff(effectful=NoEffect{Vector{Int64}}([1, 20]), length(cont)=0)
julia> function test_infers(e1, e2)
f_flatmap, e1_f = prepare_test(e1, e2)
TypeClasses.flatmap(f_flatmap, e1_f)
end
test_infers (generic function with 1 method)
julia>
julia> @inferred test_infers(e1, e2) # infers perfectly
Eff(effectful=NoEffect{Vector{Int64}}([1, 20]), length(cont)=0)
julia> combine(v1, v2) = [v1; v2]
ERROR: error in method definition: function TypeClasses.combine must be explicitly imported to be extended
Stacktrace:
[1] top-level scope
@ none:0
[2] top-level scope
@ REPL[14]:1
julia> curried_combine(v1) = v2 -> combine(v1, v2)
curried_combine (generic function with 1 method)
julia> e1_f = map(curried_combine, e1)
Eff(effectful=NoEffect{var"#10#11"{Vector{Int64}}}(var"#10#11"{Vector{Int64}}([1])), length(cont)=0)
julia> f_flatmap(f) = TypeClasses.map(v2 -> f(v2), e2)
ERROR: cannot define function f_flatmap; it already has a value
Stacktrace:
[1] top-level scope
@ none:0
[2] top-level scope
@ REPL[17]:1
julia> f_flatmap, e1_f
(f_flatmap, Eff(effectful=NoEffect{var"#10#11"{Vector{Int64}}}(var"#10#11"{Vector{Int64}}([1])), length(cont)=0))
julia> function prepare_test(e1, e2)
combine(v1, v2) = [v1; v2]
curried_combine(v1) = v2 -> combine(v1, v2)
e1_f = map(curried_combine, e1)
f_flatmap(f) = TypeClasses.map(v2 -> f(v2), e2)
f_flatmap, e1_f
end
prepare_test (generic function with 1 method)
julia>
julia> f_flatmap, e1_f = prepare_test(e1, e2)
(f_flatmap, Eff(effectful=NoEffect{var"#14#18"{Vector{Int64}, var"#combine#16"}}(var"#14#18"{Vector{Int64}, var"#combine#16"}([1], var"#combine#16"())), length(cont)=0))
julia> @inferred TypeClasses.flatmap(f_flatmap, e1_f) # infers perfectly
Eff(effectful=NoEffect{Vector{Int64}}([1, 20]), length(cont)=0)
julia> function test_infers(e1, e2)
f_flatmap, e1_f = prepare_test(e1, e2)
TypeClasses.flatmap(f_flatmap, e1_f)
end
test_infers (generic function with 1 method)
julia>
julia> @inferred test_infers(e1, e2) # infers perfectly
Eff(effectful=NoEffect{Vector{Int64}}([1, 20]), length(cont)=0)
julia> function prepare_test(e1, e2)
combine(v1, v2) = [v1; v2]
curried_combine(v1) = v2 -> combine(v1, v2)
e1_f = map(curried_combine, e1)
f_flatmap(f) = TypeClasses.map(v2 -> f(v2), e2)
f_flatmap, e1_f
end
prepare_test (generic function with 1 method)
julia> function test_infers(e1, e2)
f_flatmap, e1_f = prepare_test(e1, e2)
TypeClasses.flatmap(f_flatmap, e1_f)
end
test_infers (generic function with 1 method)
julia>
julia> @inferred test_infers(e1, e2) # infers perfectly
ERROR: return type ExtensibleEffects.Eff{NoEffect{Vector{Int64}}, Tuple{}} does not match inferred return type ExtensibleEffects.Eff
Stacktrace:
[1] error(s::String)
@ Base .\error.jl:33
[2] top-level scope
@ REPL[26]:100:
Copy and pasting this into my Julia 1.7.2 REPL results in `@inferred test_infers(e1, e2)` failing.
using Pkg
Pkg.activate(; temp = true)
Pkg.add(["ExtensibleEffects", "TypeClasses", "Test"])
using ExtensibleEffects
using TypeClasses
using Test
vector_of_eff_of_vector = map(x -> noeffect([x]), [1, 20])
e1 = vector_of_eff_of_vector[1]
e2 = vector_of_eff_of_vector[2]
function prepare_test(e1, e2)
combine(v1, v2) = [v1; v2]
curried_combine(v1) = v2 -> combine(v1, v2)
e1_f = map(curried_combine, e1)
f_flatmap(f) = TypeClasses.map(v2 -> f(v2), e2)
f_flatmap, e1_f
end
f_flatmap, e1_f = prepare_test(e1, e2)
@inferred TypeClasses.flatmap(f_flatmap, e1_f) # infers perfectly
function test_infers(e1, e2)
f_flatmap, e1_f = prepare_test(e1, e2)
TypeClasses.flatmap(f_flatmap, e1_f)
end
@inferred test_infers(e1, e2) # infers perfectly
curried_combine(v1) = v2 -> combine(v1, v2)
e1_f = map(curried_combine, e1)
f_flatmap, e1_f
function prepare_test(e1, e2)
combine(v1, v2) = [v1; v2]
curried_combine(v1) = v2 -> combine(v1, v2)
e1_f = map(curried_combine, e1)
f_flatmap(f) = TypeClasses.map(v2 -> f(v2), e2)
f_flatmap, e1_f
end
f_flatmap, e1_f = prepare_test(e1, e2)
@inferred TypeClasses.flatmap(f_flatmap, e1_f) # infers perfectly
function test_infers(e1, e2)
f_flatmap, e1_f = prepare_test(e1, e2)
TypeClasses.flatmap(f_flatmap, e1_f)
end
@inferred test_infers(e1, e2) # infers perfectly
function prepare_test(e1, e2)
combine(v1, v2) = [v1; v2]
curried_combine(v1) = v2 -> combine(v1, v2)
e1_f = map(curried_combine, e1)
f_flatmap(f) = TypeClasses.map(v2 -> f(v2), e2)
f_flatmap, e1_f
end
function test_infers(e1, e2)
f_flatmap, e1_f = prepare_test(e1, e2)
TypeClasses.flatmap(f_flatmap, e1_f)
end
@inferred test_infers(e1, e2) # now it breaks?
The session is reproducible on multiple computers. There appears to be a bug with the inference engine.
Minimized script resulting in broken inference
using Pkg
Pkg.activate(; temp = true)
Pkg.add(["ExtensibleEffects", "TypeClasses", "Test"])
using ExtensibleEffects
using TypeClasses
using Test
vector_of_eff_of_vector = map(x -> noeffect([x]), [1, 20])
e1 = vector_of_eff_of_vector[1]
e2 = vector_of_eff_of_vector[2]
function prepare_test(e1, e2)
combine(v1, v2) = [v1; v2]
curried_combine(v1) = v2 -> combine(v1, v2)
e1_f = map(curried_combine, e1)
f_flatmap(f) = TypeClasses.map(v2 -> f(v2), e2)
f_flatmap, e1_f
end
function test_infers(e1, e2)
f_flatmap, e1_f = prepare_test(e1, e2)
TypeClasses.flatmap(f_flatmap, e1_f)
end
@inferred test_infers(e1, e2) # now it breaks?
Minimal script where inference succeeds. Running `TypeClasses.flatmap(...)` has a side effect.
using Pkg
Pkg.activate(; temp = true)
Pkg.add(["ExtensibleEffects", "TypeClasses", "Test"])
using ExtensibleEffects
using TypeClasses
using Test
vector_of_eff_of_vector = map(x -> noeffect([x]), [1, 20])
e1 = vector_of_eff_of_vector[1]
e2 = vector_of_eff_of_vector[2]
function prepare_test(e1, e2)
combine(v1, v2) = [v1; v2]
curried_combine(v1) = v2 -> combine(v1, v2)
e1_f = map(curried_combine, e1)
f_flatmap(f) = TypeClasses.map(v2 -> f(v2), e2)
f_flatmap, e1_f
end
TypeClasses.flatmap(prepare_test(e1, e2)...) # infers perfectly
function test_infers(e1, e2)
f_flatmap, e1_f = prepare_test(e1, e2)
TypeClasses.flatmap(f_flatmap, e1_f)
end
@inferred test_infers(e1, e2) # infers perfectly
Minimal script where inference succeeds at first, and then fails. Redefining `prepare_test` invalidates the side effect.
using Pkg
Pkg.activate(; temp = true)
Pkg.add(["ExtensibleEffects", "TypeClasses", "Test"])
using ExtensibleEffects
using TypeClasses
using Test
vector_of_eff_of_vector = map(x -> noeffect([x]), [1, 20])
e1 = vector_of_eff_of_vector[1]
e2 = vector_of_eff_of_vector[2]
function prepare_test(e1, e2)
combine(v1, v2) = [v1; v2]
curried_combine(v1) = v2 -> combine(v1, v2)
e1_f = map(curried_combine, e1)
f_flatmap(f) = TypeClasses.map(v2 -> f(v2), e2)
f_flatmap, e1_f
end
TypeClasses.flatmap(prepare_test(e1, e2)...) # infers perfectly
function test_infers(e1, e2)
f_flatmap, e1_f = prepare_test(e1, e2)
TypeClasses.flatmap(f_flatmap, e1_f)
end
@inferred test_infers(e1, e2) # infers perfectly
function prepare_test(e1, e2)
combine(v1, v2) = [v1; v2]
curried_combine(v1) = v2 -> combine(v1, v2)
e1_f = map(curried_combine, e1)
f_flatmap(f) = TypeClasses.map(v2 -> f(v2), e2)
f_flatmap, e1_f
end
@inferred test_infers(e1, e2) # now it breaks?