Polymorphic type in instance implementation #795
-
|
Hi, I'm designing a typeclass for any instruction type, which requires the type to implement 2 functions:
The typeclass and the interface declaration looks like this: interface ExecContext#(type data_t, type operand_t, type result_t);
method operand_t#(data_t) opd1();
method operand_t#(data_t) opd2();
interface WriteOnly#(result_t#(data_t)) result;
endinterface
typeclass Instr#(type instr_t, numeric type ilen_t, type data_t, type operand_t, type result_t)
dependencies (instr_t determines (ilen_t, data_t, operand_t, result_t));
function instr_t decode(Bit#(ilen_t) raw);
function Action execute(ExecContext#(data_t, operand_t, result_t) ctx, instr_t instr);
endtypeclassNow I have an instruction type, typedef struct {
Bool is_add;
} Add;
typedef 8 ILen;
typedef Bit#(8) Data;
instance Instr#(Add, ILen, Data, Vector#(n), Vector#(n));
function Add decode(Bit#(ILen) raw);
return Add { is_add: raw % 2 == 0 }; // Example decode
endfunction
function Action execute(ExecContext#(Data, Vector#(n), Vector#(n)) ctx, Add instr) = (action
if (instr.is_add) begin
ctx.result <= zipWith(add, ctx.opd1(), ctx.opd2());
end
endaction);
endinstanceNote that I used partial application for the type However, when using the module mkFoo ();
Add a = decode(0); // <--- This line!
endmoduleThe full error message is: If I'm not taking it wrong, the I/O type for the Nonetheless, it succeeds to execute if the vector size is specified explicitly. module mkBar ();
Add a = Add {is_add: True};
// Add a = decode(0); // <--- This still failed!
ExecContext#(Data, Vector#(8), Vector#(8)) ctx = (interface ExecContext;
method Vector#(8, Data) opd1 = map(fromInteger, genVector);
method Vector#(8, Data) opd2 = map(fromInteger, genVector);
interface WriteOnly result;
method Action _write(Vector#(8, Data) result);
$display("Result is: ", fshow(result));
endmethod
endinterface
endinterface);
rule r;
execute(ctx, a); // outputs "Result is: <V 0 2 4 6 8 10 12 14 >"
$finish;
endrule
endmoduleCould someone please advise me if I’m making a mistake in my approach or suggest a solution to this issue? Also, is it a good approach to include the |
Beta Was this translation helpful? Give feedback.
Replies: 3 comments 1 reply
-
|
Furthermore, the typedef struct {
Bool is_add;
} Add;
typedef 8 ILen;
typedef UInt#(8) Data;
typedef t Scalar#(type t);
instance Instr#(Add, ILen, Data, Scalar, Scalar);
function Add decode(Bit#(ILen) raw);
return Add { is_add: raw % 2 == 0 }; // Example decode
endfunction
function Action execute(ExecContext#(Data, Scalar, Scalar) ctx, Add instr) = (action
if (instr.is_add) begin
ctx.result <= ctx.opd1 + ctx.opd2; // Scalar version of add
end
endaction);
endinstance
module mkBar ();
Add a = Add {is_add: True};
ExecContext#(Data, Scalar, Scalar) ctx = (interface ExecContext;
method Scalar#(Data) opd1 = 1;
method Scalar#(Data) opd2 = 2;
interface WriteOnly result;
method Action _write(Scalar#(Data) result);
$display("Result is: ", fshow(result));
endmethod
endinterface
endinterface);
rule r;
execute(ctx, a); // expected output: "Result is: 3"
$finish;
endrule
endmoduleIt reports an internal error: |
Beta Was this translation helpful? Give feedback.
-
|
A solution to this issue is to separate the typeclass for the typeclass Decodable#(type instr_t, numeric type ilen_t)
dependencies (instr_t determines ilen_t);
function instr_t decode(Bit#(ilen_t) raw);
endtypeclass
typeclass Executable#(type instr_t, type ctx_t);
function Action execute(ctx_t ctx, instr_t instr);
endtypeclass
typeclass Instr#(type instr_t, numeric type ilen_t, type ctx_t)
provisos (Decodable#(instr_t, ilen_t),
Executable#(instr_t, ctx_t))
dependencies (instr_t determines (ilen_t, ctx_t));
endtypeclassThe implementation: instance Decodable#(Add, ILen);
function Add decode(Bit#(ILen) raw);
return Add { is_add: raw % 2 == 0 }; // Example decode
endfunction
endinstance
instance Executable#(Add, ExecContext#(Data, Vector#(n), Vector#(n)));
function Action execute(ExecContext#(Data, Vector#(n), Vector#(n)) ctx, Add instr) = (action
if (instr.is_add) begin
ctx.result <= zipWith(add, ctx.opd1(), ctx.opd2());
end
endaction);
endinstance
instance Instr#(Add, ILen, ExecContext#(Data, Vector#(n), Vector#(n)));
endinstanceAnd the functions work as expected. module mkBar ();
Add a = decode(0); // <--- this works!!
ExecContext#(Data, Vector#(8), Vector#(8)) ctx = (interface ExecContext;
method Vector#(8, Data) opd1 = map(fromInteger, genVector);
method Vector#(8, Data) opd2 = map(fromInteger, genVector);
interface WriteOnly result;
method Action _write(Vector#(8, Data) result);
$display("Result is: ", fshow(result));
endmethod
endinterface
endinterface);
rule r;
execute(ctx, a); // outputs "Result is: <V 0 2 4 6 8 10 12 14 >"
$finish;
endrule
endmoduleHowever, I still have no luck with the |
Beta Was this translation helpful? Give feedback.
-
|
You defined The reason why you got a "vector of unknown size" error is because this instance is invalid: As you said, the type I don't fully understand what you're doing with the typeclasses, so I'm not sure I can recommend how else to write it. For example, I'm unclear why the type of the operand and result depend on the instruction. If they weren't part of the typeclass variables, then you wouldn't have this problem -- for example: Provisos on the instance could be used to require that Or, use |
Beta Was this translation helpful? Give feedback.
You defined
Scalaras a type synonym, not as a real type. That means it is like a macro, which can be inlined without changing the meaning of the code. That also means that it needs to be fully applied, can't be partially applied. BSC should have reported an error about the partial application, instead of an internal error. That is already open as Issue #221. (If you get an internal error, you can search for keywords from it, to see if there's an Issue or Discussion already open about it. For example, if you search forexpandSynortruncType, it brings up issue #221.)The reason why you got a "vector of unknown size" error is because this instance is invalid: