News for hackers. Stuff that matters.
Re:The friendship between Haskell and C by DeathArrow on Friday March 17, 2023 @07:30AM (#35195591)
Calling a C API isn't producing side effects?
Re:The friendship between Haskell and C by WJW on Friday March 17, 2023 @07:37AM (#35195644)
Not all C api calls produce (observable) side effects. As a very simple example, the sin() function from math.h is a pure function of type `Double -> Double`. No need to wrap that in IO.
Re:The friendship between Haskell and C by eesmith on Friday March 17, 2023 @09:05AM (#35196565)
The documentation for sin on a Mac says:

  sin(±infinity) returns a NaN and raises the "invalid"
  floating-point exception.
However, I can't figure out how to make that happen, and my clumsy attempts to figure out <fenv.h> and feraiseexcept() failed to make sin(INFINITY) do something other than return a NaN.
Re:The friendship between Haskell and C by jcranmer on Friday March 17, 2023 @09:33AM (#35196856)
Raising a floating-point exception generally means that the exception bit in the floating-point status register is set, and you can test this bit with fetestexcept.

Some architectures (but not all) do include some bits in the floating-point control register that will cause a hardware trap to be generated on an exception. There's no standard C function to do this, and even compiler builtin support is kind of sketchy, so your best bet is usually resorting to inline assembly to do this.

Re:The friendship between Haskell and C by eesmith on Friday March 17, 2023 @10:09AM (#35197289)
Yes, I think I was using outdated/20-year-old experience about how on the DEC Alpha a domain error like this triggered a SIGFPE, and got confused between different ideas of what "exception" means.
Re:The friendship between Haskell and C by im3w1l on Friday March 17, 2023 @11:29AM (#35198359)
I'd be concerned about whether the behavior of such a pattern is actually well defined. Like for instance what if the optimizer is super clever and evaluates your sin(infinity) at compile time? Or what if it undoes your bit-set? Or what if it moves the computation before the bit set?
Re:The friendship between Haskell and C by jcranmer on Friday March 17, 2023 @11:52AM (#35198710)
There are essentially three different flavors of floating-point models: strict, precise, and fast. Which one you get is dependent primarily on compiler flags, although most compilers will default to "precise" (a few default to "fast", but they really shouldn't).

The strict model requires that everything be evaluated at runtime and that the optimizer be aware of the potential for floating-point operations to have interactions with floating-point control and status words (i.e., rounding modes and fp exceptions)--essentially all optimizations are floating-point are forbidden.

The precise model allows compilers to ignore the dependency on rounding mode and fp exceptions, and treat floating-point optimizations as side-effect-free pure expressions, but still requires them to generally follow IEEE 754 arithmetic. As such, standard optimizations like code motion or constant propagation are legal, but arithmetic optimizations (like replacing x + 0.0 with x) are not generally legal.

The fast model allows compilers to also apply the arithmetic optimizations.

Most people who actually care about this level of detail are aware of the panoply of compiler options that are used to control floating-point optimization in the compiler.

Re:The friendship between Haskell and C by nextaccountic on Friday March 17, 2023 @01:52PM (#35200435)
How can replacing x + 0.0 with x not be legal??
Re:The friendship between Haskell and C by jcranmer on Friday March 17, 2023 @02:03PM (#35200595)
x + 0.0 is not the same as x when x is -0.0: -0.0 + 0.0 is +0.0, which is not the same as -0.0, though they do compare equal.
Re:The friendship between Haskell and C by eesmith on Friday March 17, 2023 @03:31PM (#35201743)
I decided to test every non-NaN 32-bit float, and confirmed that's the only such case.

Edit: Hee-hee! And if I put my source into Godbolt's Compiler Explorer, compile with gcc 12.2 -O3 -ffast-math then my program turns into:

  main:
          xor     eax, eax
          ret
Re:The friendship between Haskell and C by jcranmer on Friday March 17, 2023 @04:03PM (#35202132)
The other case it doesn't work is that x + 0.0 is defined to quiet an sNaN (because almost every fp operation turns sNaN to qNaN)... except even generally strict floating-point models generally say "fuck you" to sNaN and treat sNaN and qNaN as interchangeable.

(Speaking of fast math, my planned blog post title if I ever write all this up into a blog post is "Floating Point, or How I Learned to Start Worrying and Hate Fast Math.")

Re:The friendship between Haskell and C by eesmith on Friday March 17, 2023 @04:15PM (#35202295)
I deliberately added a !isnan() to my tests. There be dragons there. ;)

More precisely, my test compared the bit-patterns directly:

  i = 0 .. 2^32-1
  memcpy(&x, &i, 4);
  y = x + 0.0f;
  memcpy(&j, &y, 4)
  if (i != j) {printf("%f + 0.0 -> %f\n", x, y);
and I'm pretty sure that NaN addition, while resulting in a NaN, does not need to preserve the original bit pattern.

Regarding fast-not-so-math - Praise Kahan!

Re:The friendship between Haskell and C by jcranmer on Friday March 17, 2023 @07:31PM (#35204303)
> and I'm pretty sure that NaN addition, while resulting in a NaN, does not need to preserve the original bit pattern.

"it be complicated"

Except for certain operations (fneg, fcopysign, and fabs are all defined to only affect the sign bit, to the point that they're an exception to the sNaN-always-signals rule; and there are a few operations defined to operate on the NaN payload information), IEEE 754 generally says no more than a qNaN is generated. There's a recommendation that NaN payloads propagate, and most hardware does do that, but compilers actually typically don't even guarantee that sNaNs are not produced by operations.

Re:The friendship between Haskell and C by eesmith on Saturday March 18, 2023 @02:03AM (#35206559)
> There's a recommendation that NaN payloads propagate

I looked more closely, and yes, the signalling NaN + 0.0 always changed the bit pattern, and the quiet NaN + 0.0 always stayed the same.

Thank you for your informative details about IEEE 754.

Re:The friendship between Haskell and C by jacobmartin on Friday March 17, 2023 @09:32AM (#35196836)
You should be able to see the floating point exception by testing fetestexcept(FE_INVALID) (if it returns nonzero/true then you have a domain error). errno is also set as a side effect.

(edit), for instance this gives me output of "1":

  #include <math.h>
  #include <fenv.h>
  #include <stdio.h>

  int main(void)
  {
    double a = sin(INFINITY);
  
    printf("%d\n", fetestexcept(FE_INVALID));
    return 0;
  }
Re:The friendship between Haskell and C by eesmith on Friday March 17, 2023 @10:06AM (#35197245)
"1" on my FreeBSD/Intel box. "0" on my Mac/M1 box with the vendor cc but "1" with gcc-12.

I think I have an outdated idea that there should be a way to have the exception trigger a SIGFPE, and that modern processors don't do that.

Re:The friendship between Haskell and C by light_hue_1 on Friday March 17, 2023 @10:40AM (#35197701)
You need to enable floating point trapping. It's trivial, but it's not on by default.

Although, in that case, this function would still be pure as far as Haskell is concerned. Because its output only depends on its input. Interrupts/exceptions are outside of the scope of the type system as far as an individual function goes.

Re:The friendship between Haskell and C by jacobmartin on Friday March 17, 2023 @10:10AM (#35197300)
fascinating! Does vendor cc link to a different libc? I wonder if that is the problem and the docs are for glibc.

And testing just now, I can't even trigger SIGFPE with division by zero (integer or float). I guess all of these exceptions are "caught" now.

Re:The friendship between Haskell and C by eesmith on Friday March 17, 2023 @11:34AM (#35198418)
It took a while but I figured it out. Apple's cc compiles to:

  a.out: Mach-O 64-bit executable arm64
while my gcc-12 compiles to:

  a.out: Mach-O 64-bit executable x86_64
which is then emulated via Rosetta.
Re:The friendship between Haskell and C by jcranmer on Friday March 17, 2023 @11:58AM (#35198792)
What compilers are you using, what flags are you using with those compilers?

If you care about it, you need to use the appropriate flags to get a strict floating-point model. If you merely have a precise or fast floating-point model, calling fetestexception is going to result in unspecified behavior.

[If you really want to be strict, the result of flags are unspecified if you don't use #pragma FENV_ACCESS ON, but gcc refuses to support FENV_ACCESS pragma, and you instead need to use command-line flags to get the same effect.]

> I think I have an outdated idea that there should be a way to have the exception trigger a SIGFPE, and that modern processors don't do that.

On Intel, you can clear the exception mask for the INVALID FP exception in mxcsr and get an SIGFPE whenever an operation raises INVALID [assuming, again, strict model to ensure the optimizer respects fp exceptions.] I don't know how, or if, AArch64 can enable hardware traps on floating-point exceptions.

Re:The friendship between Haskell and C by mhh__ on Friday March 17, 2023 @11:36AM (#35198460)
errno can be set upon failure, and also the behaviour is dependant on the global floating point environment (although passing this around with you would be rather cumbersome)
Re:The friendship between Haskell and C by dllthomas on Friday March 17, 2023 @07:04PM (#35204066)
> errno can be set upon failure

... can it? I don't see it in the man page. The rest is a good point, either way, though.

Re:The friendship between Haskell and C by mhh__ on Friday March 17, 2023 @10:07PM (#35205347)
I don't know the exact wording in the standard but take a look at/around the GCC flag -fno-math-errno for example
Re:The friendship between Haskell and C by dllthomas on Friday March 17, 2023 @11:04PM (#35205641)
Ah, checked a man page on a Mac, where it never sets errno (according to the gcc docs). It's mentioned in the man page on my linux box here.
Re:The friendship between Haskell and C by epgui on Friday March 17, 2023 @07:16PM (#35204147)
That's probably true, but it's besides the point.

Haskell is not about removing side effects in the first place-- it's about making them obvious and contained, and about declaring them. It's about the type system imposing certain constraints on what's allowed and where: none of the above really applies to C.

Re:The friendship between Haskell and C by Laaas on Friday March 17, 2023 @07:35AM (#35195628)
You pretend that they don't for morally pure functions like the ones from math.h.
Re:The friendship between Haskell and C by eesmith on Friday March 17, 2023 @08:35AM (#35196259)
I remember my surprise on a DEC Alpha in late 2001 when I did something like acos(3) and the floating-point exception triggered a core dump. As I recall, on the other OSes I used, SIGFPE was by default ignored.
Re:The friendship between Haskell and C by josefx on Friday March 17, 2023 @08:44AM (#35196366)
Isn't everything in math.h spamming errno?
Re:The friendship between Haskell and C by Joker_vD on Friday March 17, 2023 @08:58AM (#35196491)
It's not an observable side effect because nobody ever observes the value of errno :)
Re:The friendship between Haskell and C by k0k0r0 on Friday March 17, 2023 @09:53AM (#35197080)
Well, this is not true. However, to be fair, most important use case of errno in my work is debugging in horrible code bases, trying to understand what has happened.
Re:The friendship between Haskell and C by cryptonector on Friday March 17, 2023 @12:17PM (#35199106)
The FFI wrappers can restore the previous value of errno after reading the newer value after calling whatever foreign function, thus undoing that side-effect, and nothing other than a signal handler could observe this side-effect in the middle of the FFI wrapper's execution.

Oh, note to self: signal handlers need to restore errno values if they call async-signal-safe functions that can set errno.

Re:The friendship between Haskell and C by ParetoOptimal on Friday March 17, 2023 @10:01AM (#35197185)
And "Fast and loose reasoning is morally correct":

http://www.cs.ox.ac.uk/people/jeremy.gibbons/publications/fa...

Re:The friendship between Haskell and C by chongli on Friday March 17, 2023 @08:58AM (#35196490)
Haskell doesn’t have side effects, but it does have effects. This is a subtle distinction that is a bit hard to explain but I’ll give it my best shot:

One way to think of Haskell is like a pure functional C preprocessor that also happens to be lazy. When Haskell code is running, pure functional expressions are being evaluated and reduced to their simplest form. This simplest form is not a plain value but actually a program that when run has effects (reading input, printing to the screen) just like a C program.

The last piece of the puzzle is that, unlike the C preprocessor, Haskell doesn’t do all of the evaluation ahead of time. The evaluation of these pure functional expressions is interwoven with the execution of the program producing the desired effects. Haskell’s type system is used to express the dependencies between inputs and outputs so that the effects are performed in the correct sequence.

Re:The friendship between Haskell and C by aidenn0 on Friday March 17, 2023 @12:02PM (#35198864)
There was a somewhat tongue-in-cheek article a while back saying "C has no side effects" with the premise being That "when people say C, they really mean CPP, because nobody writes C with the preprocessor disabled" and since CPP is side-effect free, colloquially we can say that C is side-effect free...
Re:The friendship between Haskell and C by ackfoobar on Friday March 17, 2023 @01:26PM (#35200106)
http://conal.net/blog/posts/the-c-language-is-purely-functio...

"The C language is purely functional" and "Haskell is the world's finest imperative programming language" can blow some minds.

Re:The friendship between Haskell and C by aidenn0 on Friday March 17, 2023 @02:29PM (#35200965)
That's the one.

There's also:

> “Haskell is a dynamically-typed, interpreted language.”

From https://aphyr.com/posts/342-typing-the-technical-interview

Re:The friendship between Haskell and C by goto11 on Saturday March 18, 2023 @03:44AM (#35207029)
The context is she is using Haskell type declarations as if it was a regular programming language. Arguable the type declarations are interpreted, and dynamically typed in the sense that there is no static type checking before the interpretation.
Re:The friendship between Haskell and C by marcosdumay on Friday March 17, 2023 @02:02PM (#35200576)
Hum... You meant to say that the C compiler is pure. And well, yes, it is. Even when you include the compiler itself, instead of only the preprocessor.

You can notice on the GP's description that Haskell will generate those programs at runtime. The Haskell code is running on the same level as the C compiler, but at a very different time.

Re:The friendship between Haskell and C by goto11 on Saturday March 18, 2023 @03:49AM (#35207058)
This is a very convolution way of saying that Haskell can have side effects, but some parts of the code is pure. This is also similar to any other languages. Any code is side-effect free until it is executed.

The actually interesting part of Haskell is that the type system is strong enough to indicate which sections of the code is pure and which are unpure.

Re:The friendship between Haskell and C by avgcorrection on Friday March 17, 2023 @09:45AM (#35196976)
This question returns no value (does not expect an honest answer) but has the Snark effect on the person being asked.
Re:The friendship between Haskell and C by Jeff_Brown on Friday March 17, 2023 @10:07AM (#35197254)
xmonad (a tiling window manager) and pandoc (a command-line tool for document conversion) are both written in Haskell.
Re:The friendship between Haskell and C by cryptonector on Friday March 17, 2023 @12:15PM (#35199068)
That's allowed in the IO monad, and, really, it's allowed. The idea in Haskell is to have many contexts where side effects are not allowed so that in those contexts your code must be pure, and pure code is easier to write tests for and reason about.
Re:The friendship between Haskell and C by epgui on Friday March 17, 2023 @07:11PM (#35204111)
Did anyone claim the contrary, or do you just have prejudiced ideas about Haskell?
Re:The friendship between Haskell and C by anon291 on Friday March 17, 2023 @09:29PM (#35205123)
Haskell is two languages. There's the expression language which is pure. Then there's the runtime system which takes descriptions of side effects generated by the expression language (the IO type) and executes them in the real world.

The expression language is absolutely pure.