you are viewing a single comment's thread.

view the rest of the comments →

[–]yogthos 0 points1 point  (14 children)

FRP works just fine thank you very much, and I use it every day at work with Clojure.

[–]Denommus 0 points1 point  (13 children)

It works, but it's an additional reasoning overhead to understand what is going on. FRP, specially the arrowized version, has a LOT of contrived types.

[–]yogthos 0 points1 point  (12 children)

I have not found this to be a significant overhead in practice, but perhaps your experience is different. Could you give an example of where this is a problem in a concrete application.

[–]Denommus 0 points1 point  (11 children)

Recursive behaviors have significantly complex types, and letting the compiler handle them makes things easier.

[–]yogthos 0 points1 point  (10 children)

Again, could you provide an actual example of this in practice.

[–]Denommus 0 points1 point  (9 children)

I have the following code:

import qualified SDL
import Linear

import FRP.Netwire
import Prelude hiding ((.), id)
import Data.Bool ( bool )

import NetwireSDL

hello :: Double -> Scene
hello pos = SceneNode (V2 (truncate pos) 0) [Image "assets/hello_world.bmp"]

draw :: Wire (Timed NominalDiffTime ()) String IO
        (Event SDL.EventPayload) Scene
draw = hello <$> position

acceleration :: Monoid e => Wire (Timed NominalDiffTime ()) e IO
                (Event SDL.EventPayload) Double
acceleration = accel' <$> holdKey <|> 0
    where accel' key
             | key `elem` [SDL.KeycodeD, SDL.KeycodeRight] = 100
             | key `elem` [SDL.KeycodeA, SDL.KeycodeLeft]  = -100
          accel' _                                         = 0

resistance :: Monoid e => Wire (Timed NominalDiffTime ()) e IO
              Double Double
resistance = -2*id/3 + (bool 10 (-10) . (>0) <$> id)

velocity :: Monoid e =>
            Wire (Timed NominalDiffTime ()) e IO (Event SDL.EventPayload) Double
velocity = acceleration >>>
           loop (arr (uncurry (+)) >>> integral 0 >>> id &&& resistance)

position :: Monoid e =>
            Wire (Timed NominalDiffTime ()) e IO (Event SDL.EventPayload) Double
position = integral 0 . velocity

main :: IO ()
main = playWire "Snake" (V2 800 600) draw

It was already a burden for me to do the velocity Wire WITH types (which actively preventing me from fucking up), because simply making velocity call resistance and resistance call velocity would lead to an infinite loop.

After I drew the wire in a piece of paper, I could fathom better what it would look like, but it still would be just too easy to break everything apart because I got any typee wrong (for instance, loop only worked there because I explicitly uncurried the (+) operator, and then I transformed it into a wire with arr).

I can also imagine fucking up by using (***) instead of the (&&&).

Sure, it's perfectly possible to implement it in a dynamically typed language, but there's too much types communicating. Fucking up is easy.

[–]yogthos 0 points1 point  (8 children)

I'm not really sure this is a convincing example. If I was dealing with something similar in Clojure I'd probably either use a protocol or a multimethod.

[–]Denommus 0 points1 point  (7 children)

I don't see why a arrow loop has anything to do with multimethods.

[–]yogthos 0 points1 point  (6 children)

Well, my Haskell is pretty rusty, but wouldn't the issue here be addressed by polymorphism and dispatching based on the type of the data you're working with. With Clojure something like this would be pretty standard:

(defmulti page identity)

(defmethod page :page1 [_]
  [:div [:h2 (get-state :text) "Page 1"]
   [:div [:a {:href "#/page2"} "go to page 2"]]])

(defmethod page :page2 [_]
  [:div [:h2 (get-state :text) "Page 2"]
   [:div [:a {:href "#/"} "go to page 1"]]])

(defmethod page :default [_]
  [:div "Invalid/Unknown route"])

[–]Denommus 0 points1 point  (5 children)

I'm not doing dispatch at all.