I get this:
Exception- Fail "Invalid type (not a type construction)" raised
The context: I run a toplevel built by compiling Vesa Karvonen's "extended-basis" library and doing PolyML.export (_, PolyML.rootFunction). Into this toplevel I load the enclosed Word31 module. My guess is this happens because extended-basis rebinds some basis types which are normally special-cased by the poly pretty-printer, but aren't recognized as special anymore after the rebinding. Anyway, it works ok with the normal poly.
Who's to "blame"? And is there a workaround?
structure Word31 :> WORD = struct
infix 8 << >> ~>>
type word = Word32.word
val wordSize = 31
val toLarge = Word32.toLarge
val toLargeWord = toLarge
fun toLargeX w = let open Word32 in if andb (w, 0wx40000000) = 0wx0 then toLargeX w else toLargeX (orb (w, 0wx80000000)) end
val toLargeWordX = toLargeX
fun fromLarge wl = let open Word32 in andb (fromLarge wl, 0wx7fffffff) end
val fromLargeWord = fromLarge
val toLargeInt = Word32.toLargeInt
fun toLargeIntX w = let open Word32 in if andb (w, 0wx40000000) = 0wx0 then toLargeIntX w else toLargeIntX (orb (w, 0wx80000000)) end
fun fromLargeInt i = let open Word32 in andb (fromLargeInt i, 0wx7fffffff) end
val toInt = Word32.toInt
fun toIntX w = let open Word32 in if andb (w, 0wx40000000) = 0wx0 then toIntX w else toIntX (orb (w, 0wx80000000)) end
fun fromInt i = let open Word32 in andb (fromInt i, 0wx7fffffff) end
val andb = Word32.andb
val orb = Word32.orb
val xorb = Word32.xorb
fun notb w = let open Word32 in andb (notb w, 0wx7fffffff) end
fun w << i = let open Word32 in andb (w << i, 0wx7fffffff) end
val op >> = Word32.>>
fun w ~>> i = let open Word32 in if andb (w, 0wx40000000) = 0wx0 then w ~>> i else orb (w ~>> i, 0wx40000000) end
fun w1 + w2 = let open Word32 in andb (w1 + w2, 0wx7fffffff) end
fun w1 - w2 = let open Word32 in andb (w1 - w2, 0wx7fffffff) end
fun w1 * w2 = let open Word32 in andb (w1 * w2, 0wx7fffffff) end
val op div = Word32.div
val op mod = Word32.mod
val compare = Word32.compare
val op < = Word32.<
val op > = Word32.>
val op <= = Word32.<=
val op >= = Word32.>=
fun ~ w = let open Word32 in andb (~ w, 0wx7fffffff) end
val min = Word32.min
val max = Word32.max
val fmt = Word32.fmt
val toString = Word32.toString
fun scan radix getc strm = let open Word32 in case scan radix getc strm of NONE => NONE | res as SOME (w, strm') => if andb (w, 0wx80000000) = 0wx0 then res else raise Overflow end
val fromString = StringCvt.scanString (scan StringCvt.HEX)
(* the rest is for building on top of Vesa Karvonen's mltonlib extensions *) type largeable_large = LargeWord.word
type bitwise = word
val numBytes = 4
local fun mk idx w = Word8Vector.tabulate (numBytes, fn i => (Word8.fromLarge o LargeWord.>>) (toLarge w, Word.<< (Word.fromInt (idx i), 0w3))) in val toBigBytes = mk (fn i => Int.- (Int.- (numBytes, 1), i)) val toLittleBytes = mk (fn i => i) end
val toWord8 = Word8.fromLarge o toLarge
val toWord8X = toWord8
val fromWord8 = fromLarge o Word8.toLarge
val fromWord8X = fromLarge o Word8.toLargeX
local fun mk fold bs = if numBytes <> Word8Vector.length bs then raise Subscript else fold (fn (b, w) => Word32.orb (Word32.<< (w, 0w8), fromWord8 b)) (Word32.fromInt 0) bs in val fromBigBytes = mk Word8Vector.foldl val fromLittleBytes = mk Word8Vector.foldr end
val isoWord8 = (toWord8, fromWord8) val isoWord8X = (toWord8X, fromWord8X)
val toWord = Word.fromLarge o toLarge
val toWordX = Word.fromLarge o toLargeX
val fromWord = fromLarge o Word.toLarge
val fromWordX = fromLarge o Word.toLargeX
val isoWord = (toWord, fromWord) val isoWordX = (toWordX, fromWordX)
val toFixedInt = Int32.fromLarge o toLargeInt
val fromFixedInt = fromLargeInt o Int32.toLarge
val toFixedIntX = Int32.fromLarge o toLargeIntX
val isoFixedInt = (toFixedInt, fromFixedInt) val isoFixedIntX = (toFixedIntX, fromFixedInt)
val isoLarge = (toLarge, fromLarge) val isoLargeInt = (toLargeInt, fromLargeInt) val isoLargeX = (toLargeX, fromLarge) val isoLargeIntX = (toLargeIntX, fromLargeInt) val isoInt = (toInt, fromInt) val isoIntX = (toIntX, fromInt) val isoLargeWord = isoLarge val isoLargeWordX = isoLargeX
val isoBigBytes = (toBigBytes, fromBigBytes) val isoLittleBytes = (toLittleBytes, fromLittleBytes)
fun op == (w1, w2) = w1 = w2
fun op != (w1, w2) = w1 <> w2
fun inRange (w1, w2) w = if w1 > w2 then raise Domain else w1 <= w andalso w <= w2
fun isEven w = (w andb 0wx1) = 0wx0
fun isOdd w = (w andb 0wx1) = 0wx1
fun isZero w = w = 0wx0
type bounded = word
type bounded_ex = word
val minValue = 0wx0
val maxValue = 0wx7fffffff
val largestPrime = maxValue
val bounds = (minValue, maxValue)
type formattable = word
type scannable = word
type intable = word
type largeable = word
type equality = word
type equality_ex = word
type ordered = word
type ordered_ex = word
type shiftable = word
type stringable = word
type stringable_ex = word
type wordable = word
type formattable_format = StringCvt.radix
type scannable_format = StringCvt.radix
val embString = (toString, fromString)
type t = word
end
(* Because we are using opaque signature matching we have to install type-dependent functions OUTSIDE the structure. *) local open RuntimeCalls structure Conversion = RunCall.Run_exception1 ( type ex_type = string; val ex_iden = EXC_conversion ); exception Conversion = Conversion.ex; (* The string may be either 0wnnn or 0wxXXX *) fun convWord s : Word31.word = let val radix = (* The word value must consist of at least 0w and a digit. *) if String.sub(s, 2) = #"x" then StringCvt.HEX else StringCvt.DEC in case StringCvt.scanString (Word31.scan radix) s of NONE => raise Conversion "Invalid word8 constant" | SOME res => res end
(* Install the pretty printer for Word31.word *) fun pretty(p, _, _, _) _ _ x = p("0wx" ^ Word31.toString x) in val it: unit = RunCall.addOverload convWord "convWord" val it: unit = RunCall.Inner.install_pp pretty end;
(* Add the overloaded operators. *) RunCall.addOverload Word31.~ "~"; RunCall.addOverload Word31.+ "+"; RunCall.addOverload Word31.- "-"; RunCall.addOverload Word31.* "*"; RunCall.addOverload Word31.div "div"; RunCall.addOverload Word31.mod "mod"; RunCall.addOverload Word31.< "<"; RunCall.addOverload Word31.> ">"; RunCall.addOverload Word31.<= "<="; RunCall.addOverload Word31.>= ">=";
On Dec 26, 2007 5:27 AM, Ian Zimmerman itz@madbat.mine.nu wrote:
I get this:
Exception- Fail "Invalid type (not a type construction)" raised
The context: I run a toplevel built by compiling Vesa Karvonen's "extended-basis" library and doing PolyML.export (_, PolyML.rootFunction). Into this toplevel I load the enclosed Word31 module. My guess is this happens because extended-basis rebinds some basis types which are normally special-cased by the poly pretty-printer, but aren't recognized as special anymore after the rebinding. Anyway, it works ok with the normal poly.
Who's to "blame"? And is there a workaround?
I took a look at this. I would argue that this is a bug in Poly/ML, although, of course, overloading isn't a part of the Definition, so technically Poly/ML can specify it freely. The problem is around line 2732 in VALUE_OPS.ML. The problem is that the case there only accepts the FunctionType variant and does not expand type constructions. IOW, the overload code doesn't work with type abbreviations. The extended-basis library uses type abbreviations heavily. The value Word32.+ from the extended.basis lib is printed as
val it = fn : MkWordExt().Core.t BIN_OP.t
by Poly/ML. An attempt to add an overload for it gives the above mentioned error, because Poly/ML's overload code does not expand the BinOp.t type constructor to recognize it as an arrow type. You can work around this by ascribing the value explicitly with an arrow type:
RunCall.addOverload (Word32.+ : Word32.t * Word32.t -> Word32.t) "+";
(In your case, of course, you'd do the same for Word31 instead of Word32. You don't need Word31 to expose this problem.)
BTW, it didn't take a lot of time to diagnose this problem. I first reproduced the problem. Then I updated my cvs copy of Poly/ML and rebuilt it while getting a cup of coffee. Then I spent a few minutes playing in the Poly/ML REPL looking, among other things, the types of values and trying to add overloads (most of this time wasn't very productive, though). Then I grepped for the error message from Poly/ML's code and got two hits. After browsing the code for a few minutes, I realized what the problem was after following the code to see where the typeToUse value (line 2761) passed to followTypes (that raises the error) came from.
-Vesa Karvonen
Vesa Karvonen wrote:
On Dec 26, 2007 5:27 AM, Ian Zimmerman itz@madbat.mine.nu wrote:
I get this:
Exception- Fail "Invalid type (not a type construction)" raised
Who's to "blame"? And is there a workaround?
I took a look at this. I would argue that this is a bug in Poly/ML, although, of course, overloading isn't a part of the Definition, so technically Poly/ML can specify it freely. The problem is around line BinOp.t type constructor to recognize it as an arrow type. You can work around this by ascribing the value explicitly with an arrow type:
RunCall.addOverload (Word32.+ : Word32.t * Word32.t -> Word32.t) "+";
(In your case, of course, you'd do the same for Word31 instead of Word32. You don't need Word31 to expose this problem.)
Since there seems to be a work-around for this problem I don't feel it's worth spending any effort on fixing. If someone wants to provide a patch I'll certainly consider it. The RunCall structure is only intended to be used for writing Poly-specific libraries and not for average users. Some of the functions in it are very unsafe, such as the arbitrary cast, so any use of it is "at user's own risk".
By the way, on all 32-bit platforms other than Sparc Word is actually Word31 so you probably don't need to re-implement it.
David.
David> By the way, on all 32-bit platforms other than Sparc Word is David> actually Word31 so you probably don't need to re-implement it.
But there is no actual Word31 structure?
Word.wordSize ;
val it = 31 : int
Word31.wordSize ;
Error: Structure (Word31) has not been declared Found near Word31.wordSize
Static errors (pass2)
Of course for my own purposes I can just do "structure Word31 = Word" but that isn't enough when building with Vesa's library since it extends the WORD signature.
Best regards, Ian.
On Dec 28, 2007 4:14 PM, Ian Zimmerman itz@madbat.mine.nu wrote:
David> By the way, on all 32-bit platforms other than Sparc Word is David> actually Word31 so you probably don't need to re-implement it.
But there is no actual Word31 structure?
[...]
Of course for my own purposes I can just do "structure Word31 = Word" but that isn't enough when building with Vesa's library since it extends the WORD signature.
Can you do the "structure Word31 = Word" binding after evaluating the extended basis?
-Vesa Karvonen