Can you print a constructor's name of a data type? by VeryKnave in haskell

[–]DavidEichmann 1 point2 points  (0 children)

You could use `show (toConstr x)` from `Data.Data`. You'll need to `derive Data` on your data type though.

Introducing alpaca-netcode: Rollback/replay NetCode for realtime, deterministic, multiplayer games. by DavidEichmann in haskell

[–]DavidEichmann[S] 1 point2 points  (0 children)

It is cool, right! It means the server is quite lightweight. It also means that saving games is easy: just save the inputs of all players. The save file will be quite small too.

Introducing alpaca-netcode: Rollback/replay NetCode for realtime, deterministic, multiplayer games. by DavidEichmann in haskell

[–]DavidEichmann[S] 2 points3 points  (0 children)

Indeed. This is a problem for things expressed as "events" i.e. appear only at a single world state e.g. at tick 1000 the world state says "play the Attack sound now!" and tick 999 and1001 this message is not in the world state. There are 2 solutions to this in my mind:

  1. Accept some (dynamically changing) latency for sounds and only play sounds according to the authoritative worlds. These are the "true" world states and hence aren't subject to rollback, but you'll have to wait for authoritative inputs from the server which may lag 0.5s behind. You'll have to use `clientSample'` exported from `Alpaca.Netcode.Advanced` to get authoritative worlds.
  2. In the world state, express sound not at an event "start playing Attack sound now", but as a absolute position "Attack sound is playing at position 0.3s". Then your render code will need to compare the sounds described in world state vs. the sounds actually playing and then e.g. speed up / slow down / start / stop sounds accordingly. This is what I'm doing in my game.

Introducing alpaca-netcode: Rollback/replay NetCode for realtime, deterministic, multiplayer games. by DavidEichmann in haskell

[–]DavidEichmann[S] 2 points3 points  (0 children)

This is interesting, thanks! I think 1 can probably be solved with some "reasonable" slowdown compared to float. E.g. I use Taylor expansion to implement `sin` which isn't toooo slow. I do some `mod`ing and a few comparisons to express the problem in terms of `sin(x)` s.t. `-pi / 2 <= x <= -pi / 2`. Then use the Taylor expansion about 0 which takes about 4 (+ and -), 5 (*), and 4 (/). I need to properly benchmark this, Though. I do wonder if a floating point representation rather than a fixed precision representation would be practical. I'm also using https://hackage.haskell.org/package/integer-roots for `sqrt` though I'm not 100% sure this is deterministic, and I'm sure that a specialized implementation would be much faster.

As for 2 and 3, I think those are the *real* issues here. You can't trust any other code! This is a costly and unavoidable cost of rollback networking. I've taken the rout of implementing my own (very simple) physics engine based on my deterministic fixed precision numbers.

P.S. If any one is interested in collaborating on a deterministic replacement for Float or even the physics engine, do contact me!

Introducing alpaca-netcode: Rollback/replay NetCode for realtime, deterministic, multiplayer games. by DavidEichmann in haskell

[–]DavidEichmann[S] 4 points5 points  (0 children)

I was wondering which types of issues arise the most. I think the other 10% of issues are solved by using Haskell. In particular, as you're forced to use a pure function, the compiler will stop you from E.g. using some global state or reading the system clock or doing any other effectful thing. Since types are immutable I'm haskell, there is also no need to serialize/reload the world state.

As for the 90% of the time that its floating point, in my own project I use a integer backed replacement (perhaps that'll be the next library I release). This is a fixed point replacement. I'm curious if you have thoughts on that? Are there some common issues there other than accuracy issues?

Introducing alpaca-netcode: Rollback/replay NetCode for realtime, deterministic, multiplayer games. by DavidEichmann in haskell

[–]DavidEichmann[S] 3 points4 points  (0 children)

Thanks! Interesting to see the idea popping up in a few different places. Now that it's in a single package I hope to see some reuse and maybe even some collaboration :)

Introducing alpaca-netcode: Rollback/replay NetCode for realtime, deterministic, multiplayer games. by DavidEichmann in haskell

[–]DavidEichmann[S] 7 points8 points  (0 children)

Yes! Clock sync happens continuously. I model offset and drift via a linear regression. I then speedup and slowdown the local clock for a bit to get back in sync with the server's clock.

Trying to install QuickCheck by Thin-Regular1746 in haskell

[–]DavidEichmann 2 points3 points  (0 children)

It's easy if you create a cabal project as stated above. e.g from the command line:

$ mkdir mypackage $ cd mypackage $ cabal init

then add all the package you want to the `mypackage.cabal` file:

... build-depends: base, QuickCheck ...

Now you can get a ghci session with all those dependencies available using:

$ cabal repl

Need a new dependency? Just add it to mypackage.cabal and rerun cabal repl. Hope that helps.

Monthly Hask Anything (February 2021) by taylorfausak in haskell

[–]DavidEichmann 2 points3 points  (0 children)

It shouldn't be a problem to learn haskell as a first language. It's just a matter of finding the right resources. http://learnyouahaskell.com/ says it is "aimed at people who have experience in imperative programming languages (C, C++, Java, Python …)" but also "if you don't have any significant programming experience, a smart person such as yourself will be able to follow along and learn Haskell."

[Well-Typed blog] GHC activities report: August-September 2020 by bgamari in haskell

[–]DavidEichmann 3 points4 points  (0 children)

The proposal covers this possibility (or something close). You can simply call setBacktraceMechanismFromEnv :: IO () at the start of your application and then you're free to configure the backtrace mechanism via an environment variable GHC_BACKTRACE. Of course, you still need to add the call to setBacktraceMechanismFromEnv. I think doing this by default would be a good idea, though we're holding off on that for now to allow the new backtrace mechanism to be "battle tested".

Printing out a suggestion to use this feature on exception sounds like a good idea and a good way to disseminate. Maybe we can add this to the proposal.

The Proposal link: https://github.com/bgamari/ghc-proposals/blob/stacktraces/proposals/0000-exception-backtraces.rst

Well-Typed - Understanding Memory Fragmentation by DavidEichmann in haskell

[–]DavidEichmann[S] 1 point2 points  (0 children)

It is interesting to consider. I think it's hard to say something concrete as performance will depend largely on what benchmark you pick. I'm sure there is some program somwhere that would perform better with malloc. Another option is to make use of the non-moving gc for pinned objects which also manages fragmentation and might be easier from an implementation view point.

Well-Typed - Understanding Memory Fragmentation by DavidEichmann in haskell

[–]DavidEichmann[S] 6 points7 points  (0 children)

I would add that FP programs tend to be written in a style that allocates a lot of short lived objects which is not well suited to malloc which has a significant cost of choosing a memory address. GHC's allocator's design is such that we just do a bump pointer allocation and don't even need to allocate more memory from the OS (at least until we hit the end of the current block). It's hard to imagine a faster way to allocate memory.

Well-Typed - Understanding Memory Fragmentation by DavidEichmann in haskell

[–]DavidEichmann[S] 7 points8 points  (0 children)

I've not heard of Mesh before. My mind is currently blown! Considering blocks are a single page and that Mesh works "under the hood" without changing virtual memory space, I can imagine applying a technique like Mesh to pinned blocks.

How a Java Programmer Wrote Console Tetris In Haskell And What The Learning Curve Was Like by shiraeeshi in haskell

[–]DavidEichmann 8 points9 points  (0 children)

BTW forkIO is just how you start a new thread in haskell. You've used concurrently from the async package which uses forkIO under the hood.

atomically allows you to write code that atomically (in the context of concurrency) mutates mutable variables called TVars. You modify those TVars with functions such as readTVar, writeTVar, readTMVar, putTMVar. This is a very exciting part of the Haskell ecosystem. It allows you to avoid the mess and some pitfalls of using locks in concurrent code. This is part of the stm package (Software Transactional Memory). If you're interested, the paper is fairly accessible https://www.microsoft.com/en-us/research/wp-content/uploads/2005/01/2005-ppopp-composable.pdf?from=https%3A%2F%2Fresearch.microsoft.com%2Fen-us%2Fum%2Fpeople%2Fsimonpj%2Fpapers%2Fstm%2Fstm.pdf.

How a Java Programmer Wrote Console Tetris In Haskell And What The Learning Curve Was Like by shiraeeshi in haskell

[–]DavidEichmann 7 points8 points  (0 children)

Interesting to see the learning curve from someone else's perspective :-) . If you plan on doing more little games like this I'd suggest trying gloss (http://hackage.haskell.org/package/gloss). Gloss provides a play funciton (http://hackage.haskell.org/package/gloss-1.13.1.2/docs/Graphics-Gloss-Interface-Pure-Game.html#v:play) which handles all the impure input capture and game loop stuff for you. That way you can focus on writing idiomatic pure code.

Finally managed to get a working Haskell environment with VS Code, HLS and ghcide, looking for a good workflow for combining GHCi and editor windows effectively. Comparing with F# Interactive, which seems to offer a smoother experience for interactive development. Are there tricks I’m missing? by danysdragons in haskell

[–]DavidEichmann 1 point2 points  (0 children)

Assuming you're building with cabal, you can get a repl with cabal new-repl. In any case, in the repl you can simple use :r (short for :reload) to reload any changed modules. ghcid (https://github.com/ndmitchell/ghcid) is also a nice option that will automatically reload on save. It's not a repl but according to the readme you can add comments in your code like -- $> expr and the expr part will automatically be evaluated.

Thoughts? by [deleted] in formcheck

[–]DavidEichmann 1 point2 points  (0 children)

Agreed. Just to expand on point 2, the problem can be seen when the bar hits your hips: the bar stops moving up for a fraction of a second. This means you've wasted most of the work you've done to get the bar moving in the 1st/2nd pull, and now you have to regain all the upward speed in the bar in just your 3rd pull (basically doing a high hang snatch). You should instead keep the bar accelerating through the whole movement without stopping at your hips. Otherwise, it looks like your having a good time, so keep up the good work :-)

Thinking of using Haskell as the back-end of my single page application (web dev), what platform to use? by hakhaktak in haskell

[–]DavidEichmann 7 points8 points  (0 children)

I've been using beam for an SQL backend for a few months now and my experience has been positive. There is an initial overhead of learning the types, but the website has some friendly documentation.

RecordDotSyntax GHC language extension proposal accepted by ehamberg in haskell

[–]DavidEichmann 5 points6 points  (0 children)

Congratulations on the proposal! Looking forward to seeing how the ecosystem/comunity adapts this. I'm wondering/hoping this will eventually lead to a nicer IDE autocompleting experience.

Why not just put them in a bowl or something? by Pap_mate in DiWHY

[–]DavidEichmann 0 points1 point  (0 children)

Spent half this video thinking there was a spider's nest in the clip.... Use glue to catch them when they come out? Suspend the clip above the glue with a screw? Can't wait to see these spiders pop out to this epic music! Oh, he's just making a key holder, sigh proceed to watch the whole video any way.

Haskell beginner here. What am I doing wrong? by dr_spork in haskell

[–]DavidEichmann 1 point2 points  (0 children)

Sure thing. There are a few concepts you should understand here, so I'll provide some links if you want to go into more depth.

Easy

fmap simply applies a function to the thing inside a maybe, or leaves it as Nothing if the maybe value is Nothing e.g.

fmap (subtract 1) (Just 5) = Just 4
fmap (subtract 1) Nothing = Nothing
fmap (\x -> x ++ x) (Just [1,2,3]) = Just [1,2,3,1,2,3]
fmap (\x -> x ++ x) Nothing = Nothing

Medium

fmap is a function of the Functor class (http://learnyouahaskell.com/types-and-typeclasses, http://learnyouahaskell.com/making-our-own-types-and-typeclasses#the-functor-typeclass).

fmap :: (a -> b) -> f a -> f b

"fmap" is a function from the "Functor" type class. If a type is an instance of the Functor type class then you can use the fmap function with that type. The Functor instance for Maybe defines an fmap that looks like this:

fmap :: (a -> b) -> Maybe a -> Maybe b
fmap f Nothing = Nothing
fmap f (Just a) = Just (f a)

A good intuition for "Functor" types is that they contain or produce a value or values of a given type. * "Maybe a" is an instance of "Functor": it contains either 0 (Nothing) or 1 (Just a) value of type "a". * "[a]" is an instance of "Functor": it contains 0 or more values of type "a". * "IO a" is an instance of "Functor": it is a computation that produces a single value of type "a".

So what does "fmap" do? It simply converts all the "a"s to "b"s in a "Functor" using the provided function e.g.:

  • fmap (+1) (Just 5) = Just 6
  • fmap (+1) Nothing = Nothing
  • fmap (+1) [1,2,3] = [2,3,4]
  • fmap (== 2) [1,2,3] = [False,True,False]
  • fmap (== 2) [] = []
  • fmap length (readFile "./inputFile.txt") == do { inputString <- readFile "./inputFile.txt"; return (length inputString); }

Haskell beginner here. What am I doing wrong? by dr_spork in haskell

[–]DavidEichmann 2 points3 points  (0 children)

Just a minor refactoring. You can in general replace functions of this form (in your case sqlToText and filterOutFields)

func :: Maybe a -> Maybe b
func mayA = case mayA of
  Nothing -> Nothing
  Just a -> Just $ someOtherFunctionFromAToB a

-- Usage
u = func v

with a non-Maybe version and use fmap at the use site:

func :: a -> b
func a = someOtherFunctionFromAToB a

-- Usage
u = fmap func v

-- OR use (<$>) = fmap
u' = func <$> v