# Hugs

Hugs is an interpreter for the Haskell programming language.

It is a good solution for small systems, needing very little disk space and memory. It is much slower than GHC when evaluating code, but it starts almost instantaneously.

It has nicer error reporting than GHC. But it supports far fewer language extensions than GHC.

However, it is no longer maintained, and the Debian package is orphaned.

# 1 Behaviour

Hugs behaves differently from GHC in some ways.

# 1.1 fromInteger

In Hugs, fromInteger :: Integer -> Int throws arithmetic overflow exceptions on out of range. In GHC it truncates silently.

# 1.2 round

In Hugs, round (1/0) :: Integer throws arithmetic overflow. In GHC a large number is returned silently.

Similar behaviour in ceiling, floor, truncate.

# 1.3 log

In Hugs, log 0 throws an argument out of range exception. In GHC it returns negative infinity.

In Hugs, log (-10) throws an argument out of range exception. In GHC it returns NaN.

In Hugs, log (0/0) throws an argument out of range exception. In GHC it returns NaN.

# 1.4 sqrt

Similar to log, apart from sqrt 0 is ok.

# 2 Patches

Hugs has some bugs. Here are some I found, with fixes.

Patches against apt source hugs98 on Debian testing/Bookworm.

# 2.1 toInteger

Problem: toInteger (minBound :: Int) returns nonsense on 64-bit systems. May also affect 32bit systems, but I haven’t checked (I checked on Debian Linux).

Cause: -INT_MIN == INT_MIN.

Symptoms: bitwise operations on Integer throw arithmetic overflow exceptions.

Solution:

diff -wur old/hugs98-98.200609.21/src/bignums.c new/hugs98-98.200609.21/src/bignums.c
--- old/hugs98-98.200609.21/src/bignums.c	2004-10-29 13:43:09.000000000 +0100
+++ new/hugs98-98.200609.21/src/bignums.c	2023-02-01 11:15:18.575315477 +0000
@@ -117,7 +117,7 @@
 	unsigned long no;
 	Cell nx;
 	if (n<0) {
-	    no = (unsigned long)(-n);
+	    no = (unsigned long)(-(signed long)(n));
 	    bn = pair(NEGNUM,NIL);
 	}
 	else {

# 2.2 isNaN and friends

Problem: isNaN and friends always return False.

Cause: they’re implemented that way.

Symptoms: code that checks floating point values are ok to handle errors does nothing, then later code that assumes finite values throws arithmetic overflow exceptions.

Solution:

diff -wur old/hugs98-98.200609.21/libraries/hugsbase/Hugs/Prelude.hs new/hugs98-98.200609.21/libraries/hugsbase/Hugs/Prelude.hs
--- old/hugs98-98.200609.21/libraries/hugsbase/Hugs/Prelude.hs	2006-05-03 10:10:40.000000000 +0100
+++ new/hugs98-98.200609.21/libraries/hugsbase/Hugs/Prelude.hs	2023-02-02 15:47:18.561731245 +0000
@@ -275,6 +275,9 @@
     scaleFloat       :: Int -> a -> a
     isNaN, isInfinite, isDenormalized, isNegativeZero, isIEEE
 		     :: a -> Bool
+    isNaN x          = not (x == x)
+    isInfinite x     = (1 / x) == 0
+    isNegativeZero x = x == 0 && 1 / x < 0
     atan2	     :: a -> a -> a
 
     -- Minimal complete definition: All, except exponent, signficand,
@@ -972,10 +975,7 @@
     floatRange  _ = (primFloatMinExp, primFloatMaxExp)
     encodeFloat = primFloatEncode
     decodeFloat = primFloatDecode
-    isNaN       _ = False
-    isInfinite  _ = False
     isDenormalized _ = False
-    isNegativeZero _ = False
     isIEEE      _ = False
 
 primitive primDoubleRadix  :: Integer
@@ -991,10 +991,7 @@
     floatRange  _ = (primDoubleMinExp, primDoubleMaxExp)
     encodeFloat   = primDoubleEncode
     decodeFloat   = primDoubleDecode
-    isNaN       _ = False
-    isInfinite  _ = False
     isDenormalized _ = False
-    isNegativeZero _ = False
     isIEEE      _ = False
 
 instance Enum Float where