Integrated Dynamics

Integrated Dynamics

63M Downloads

Server Crash with Compound Operator

JHawkley opened this issue ยท 7 comments

commented

Issue type:

  • ๐Ÿ› Bug

Short description:

I was hoping this issue would be fixed with the latest version, but it seems it is not yet.

In an attempt to create an operator that binds two values and then waits for an operator to apply to it, I'm able to create an operator that reliably crashes the server.

This issue may be related to #751.

Steps to reproduce the problem:

Due to the complex nature of the operator, I'll use some pseudo-code to describe how I built the offending operator.

Notes on the pseudo-code:

  • Any place you see a var is where a variable card was bound in the Logic Programmer.
  • The string in the back-ticks is the name I gave the variable card using a Labeller.
  • The type that I think the variable card should evaluate to follows the colon; generic-types are used to aid clarity.
  • Operator application is Haskell-style.
  • Operators applied via the Logic Programmer are in camelCase.
// Creating the offending `Op@Bind2` operator.

var `Op@Apply2`: (A -> B -> C) -> A -> B -> C
  = operatorByName "Operator Apply 2";

var `Op@Flip`: (A -> B -> C) -> (B -> A -> C)
  = operatorByName "Operator Flip";

var `Op@Apply2 Flipped`: A -> (A -> B -> C) -> B -> C
  = flip `Op@Apply2`;

var `Op@Bind2`: A -> B -> (A -> B -> C) -> C
  = pipe `Op@Apply2 Flipped` `Op@Flip`;

// Attempting to use the `Op@Bind2` operator.

var `Int@4`: Integer
  = integer 4;

var `Int@8`: Integer
  = integer 8;

var `Op@Bound<4, 8>`: (Integer -> Integer -> C) -> C
  = apply2 `Op@Bind2` `Int@4` `Int@8`;

var `Op@Addition`: Number -> Number -> Number
  = operatorByName "Arithmetic Addition";

var `Integer@Addition Result`: Integer
  = apply `Op@Bound<4, 8>` `Op@Addition`;

When the Integer@Addition Result variable card is placed into a Displayer, Proxy, or Materializer, the server crashes.

The server can be restarted and the variable card removed by breaking the object that contains it. The network may need to be reinitialized by breaking a logic cable and replacing it before it will begin evaluating a program again.

Expected behaviour:

At best, I expect the Integer@Addition Result variable card to evaluate to 12.

At worst, I expect that it does not crash the server, and catches and displays an error to the user in the GUI of the device the Integer@Addition Result variable card is placed into.

This is probably related to a lack of proper eta-conversion, and it would be fine if this particular program fails for that reason, but it certainly should not crash the server.


Versions:

  • This mod: 1.0.16
  • Minecraft: 1.12.2
  • Forge: 14.23.5.2836
  • Mod pack: Enigmatica 2: Expert, version 1.65d

Log file:

The crash-log produced by this crash is available on PasteBin.

commented

Thanks for reporting, I'll look into it as soon as possible!

commented

I believe this happens because pipe doesn't act how you'd normally expect here due to the more rigid treatment of functions here than in normal lambda calculus.

I think according to ID, your Op@Bind2 is less A -> B -> (A -> B -> C) -> C and more A -> (B -> (A -> B -> C) -> C) which is different (according to ID's type system). This can be seen by materializing Op@Bind2 to get a signature of Any -> Operator showing this to indeed be a lack of eta conversion.

I think this is also related to #352 in the sense that there are various places where eta conversions are not done where someone familiar with lambda calculus or haskell would assume they are.

To work around issues like this, I have found that materializing often to check what ID thinks the signature is to be quite helpful. You can then use apply (or apply2 or apply3) liberally to force some eta abstractions. In this case, instead of using apply2 on Op@Bind2, first just apply one integer. This results in the eta abstraction of the Operator that Bind2 thinks it's returning.

commented

Oh, don't worry. I do understand what is happening to the operator signatures under-the-hood.

The use of Haskell-style type annotations for operators makes me really wanna believe that we're dealing with operator :: A -> B -> C, functions with single arguments which return other functions, and not operator (A, B): C, functions that have a C-style parameter-list and require multiple arguments to be supplied before returning any kind of value.

I think how the operators present their types right now is confusing and misleading, and I'm more or less trying to hammer that point home by ignoring the actual reality. ๐Ÿ˜›

Honestly, I'm really wanting to dig into this code-base and add in generics (to get stronger type checking in the Logic Programmer), eta-conversions, guards (or type-tags as I'm currently calling them in my head), tuples, patterns and pattern-matching, and a lot of other features that I think would benefit the player and make the creation of programs easier and more intuitive.

I've been slowly familiarizing myself with the code-base, more or less in preparation for contributing. Maybe I should get on the Discord and see if I can coordinate.

Anyways, regardless of what is happening with the types of the operators produced by my shenanigans, this particular sequence still shouldn't crash the server. ๐Ÿ˜›

commented

FYI, I have been breaking my head over this one, but I nearly have a fix.

Also, any contributions are definitely welcome!

commented

Fix incoming...

2019-07-10_21 39 10

commented

Wowie~ Just noticed and looked through the commit. It sure does! This is gonna really make things so much smoother. Thanks for putting in the effort for the best result. ๐Ÿ˜Š

commented

Oh my god, it says 12.

Does this mean you updated the apply operators to perform sequential application when the supplied operator has less arity than the number of values it was supplied? That would basically be a proper eta-conversion.

I think that's the only way the program I supplied could possibly produce 12.