1) The wiki page showed I could use ParametricLine(Correct) == Student to check; this example shows the Student thing can be constructed within the checker subroutine.
2) The object $XYZ, and its pieces, needed to exist for display in my solution; using a global object for Correct during the check simplified the subroutine code.
$hi = 15 ;
$lo = -$hi ;
$a = non_zero_vector3D( $lo , $hi , 1 ) ;
do {$b = non_zero_vector3D($lo,$hi,1)} until not( areParallel $a $b ) ;
#### points are not collinear because a,b =/= 0 and a |/| b
$P = non_zero_point3D( $lo , $hi , 1 ) ;
$Q = Point( $P + $a ) ;
$R = Point( $P + $b ) ;
($Px,$Py,$Pz) = $P -> value ;
$QR = Vector($R) - Vector($Q) ; #### = b - a
($vx,$vy,$vz) = $QR -> value ;
$X = Formula( "$Px + ($vx * t)" ) -> reduce ;
$Y = Formula( "$Py + ($vy * t)" ) -> reduce ;
$Z = Formula( "$Pz + ($vz * t)" ) -> reduce ;
$Pv = Vector( $P ) ; #### cosmetic, show <...> in solution
$XYZ = Vector( "$Pv + t * $QR" ) ;
#### input establishes dimension and type
#### use global $XYZ for checking rather than constructing it inside sub
$LineCheck = MultiAnswer( $X , $Y , $Z ) -> with(
singleResult => 1 ,
checker => sub {
my ( $C , $S , $self ) = @_ ;
## get student components, ensure we use formulas, eval & diff them
my ($sx , $sy , $sz) = @{$S} ;
my ($Sx , $Sy , $Sz) = ( Formula($sx), Formula($sy), Formula($sz) ) ;
my @S0 = ( $Sx->eval(t=>0) , $Sy->eval(t=>0) , $Sz->eval(t=>0) );
my ($Sx1, $Sy1, $Sz1) = ( $Sx -> D , $Sy -> D , $Sz -> D ) ;
my $stuPoint = Vector( $S0[0] , $S0[1] , $S0[2] ) ;
my $stuDirec = Vector( $Sx1 , $Sy1 , $Sz1 ) ;
my $stuLine = Vector( "$stuPoint + t * $stuDirec" ) ;
return ParametricLine( $XYZ ) == $stuLine ;
## ParametricLine has its own check that formula is linear in t
}
) ;