When writing a function by matching patterns by values ββGADT GHC uses information about the expected behavior during the execution of your function when checking each sentence. Your vAppend function has only one sentence, this template corresponds to a value of type Vec nb and another value of type Vec mb . The GHC explains that if, at run time, vAppend is applied to actual arguments that match the T pattern, then the actual type of the actual arguments should be Vec VZero b , which is more informative than just Vec nb or Vec mb . The way this reasoning is implemented in the GHC is that when checking the RHS type of the unique vAppend it fixes the assumption that n must be really VZero , n ~ VZero , as well as m ~ VZero .
The type you write for the function sets up the contract that it must execute. The error message you receive is related to the fact that the contract that must be executed when implementing vAppend is too general. You say that, given two vectors of length n and m , vAppend should create a vector that can be considered any size. Indeed, the GHC notices that your implementation does not fulfill this contract, because the type of your RHS Vec VZero b does not match the expected type of RHS, Vec nm b , and there is no assumption that nm ~ VZero . Indeed, the only assumptions available to us, says the GHC, are those from the previous paragraph.
The only possible way to fulfill this contract is to write undefined as the RHS of your proposal. This is clearly not what you want. The trick to getting the right type for vAppend is to somehow relate the size of the output vector to the corresponding size of the two input vectors. It might look like this:
type family Plus nm type instance Plus VZero m = m type instance Plus (VSucc n) m = VSucc (Plus nm) vAppend :: Vec nb -> Vec mb -> Vec (Plus nm) b vAppend TT = T
We said here that the length is determined by the lengths of the inputs before vAppend , through some function on types called Plus . In the case where both VZero input VZero , we know that Plus nm same as Plus VZero VZero , since n ~ VZero and m ~ VZero . Since Plus VZero VZero is in the form of an instance of the first type family, GHC knows that it matches VZero . Therefore, in this thread, the GHC expects RHS like Vec VZero b , which we can easily build!
source share