All the side effects were never mentioned to me
I am innocent of uncontrolled abuse

  • 117 Posts
  • 37 Comments
Joined 1 year ago
cake
Cake day: June 17th, 2023

help-circle










  • Stream fusion does work:

    data Stream a = forall s. Stream !(s -> Step s a) !s
    data Step s a = Yield a !s | Skip !s | Done
    
    data Tup a b = Tup !a !b
    
    cartesianProduct :: Stream a -> Stream b -> Stream (a, b)
    cartesianProduct (Stream step1 s01) (Stream step2 s02) = Stream step' s' where
      s' = Tup s01 s02
      step' (Tup s1 s2) =
        case step1 s1 of
          Yield x s1' ->
            case step2 s2 of
              Yield y s2' -> Yield (x, y) (Tup s1 s2')
              Skip s2' -> Skip (Tup s1 s2')
              Done -> Skip (Tup s1' s02)
          Skip s1' -> Skip (Tup s1' s2)
          Done -> Done
    
    eft :: Int -> Int -> Stream Int
    eft x y = Stream step x where
      step s
        | s > y = Done
        | otherwise = Yield s (s + 1)
    
    fooS :: Stream (Int, Int)
    fooS = cartesianProduct (eft 0 10) (eft 0 10)
    
    toList :: Stream a -> [a]
    toList (Stream step s0) = go s0 where
      go !s =
        case step s of
          Yield x s' -> x : go s'
          Skip s' -> go s'
          Done -> []
    
    foo :: [(Int,Int)]
    foo = toList fooS
    
    


  • Admittedly it gets more complicated when summing two things at the same time:

    let Pair dnormMean dnormNormMean =
          fold (Pair <$> dimap (\(Pair _ dnormI) -> dnormI) (/ fromIntegral cc) sum
                     <*> dimap (\(Pair normBti dnormI) -> normBti * dnormI) (/ fromIntegral cc) sum)
            $ map (\i -> Pair (((inp ! (off + i)) - meanBt) * rstdBt)
                              ((weight ! i) * (dout ! (off + i))))
              [0 .. cc - 1]
    
    
    float dnorm_mean = 0.0f;
    float dnorm_norm_mean = 0.0f;
    for (int i = 0; i < C; i++) {
        float norm_bti = (inp_bt[i] - mean_bt) * rstd_bt;
        float dnorm_i = weight[i] * dout_bt[i];
        dnorm_mean += dnorm_i;
        dnorm_norm_mean += dnorm_i * norm_bti;
    }
    dnorm_mean = dnorm_mean / C;
    dnorm_norm_mean = dnorm_norm_mean / C;
    
    















  • We can make it a lot more performant, shorter, and also safer by using lazy byte strings:

    {- cabal:
    build-depends: base, network, network-run, bytestring
    -}
    
    {-# LANGUAGE OverloadedStrings #-}
    
    import Network.Run.TCP (runTCPServer)
    import qualified Network.Socket.ByteString.Lazy as Net
    import qualified Data.ByteString.Lazy.Char8 as Str
    
    main = runTCPServer (Just "127.0.0.1") "9999" $ \s -> do
      request <- Net.getContents s
      case Str.words (Str.takeWhile (/= '\r') request) of
        ["GET", resource, "HTTP/1.1"] -> do
          let path = Str.concat
                [ "htdocs/"
                , Str.dropWhile (== '/') resource
                , if Str.last resource == '/' then "index.html" else ""
                ]
          page <- Str.readFile (Str.unpack path)
          Net.sendAll s ("HTTP/1.1 200 OK\r\n\r\n" <> page)
        _ -> error "todo"
    
    










  • I think Idris’ bang notation for performing effects in a do-block is pretty, it could look like this:

    main = do putStrLn ("You said: " ++ !getLine)
    
    

    Today, you’d have to come up with a new variable name or figure out the right combinator names:

    main = do line &lt;- getLine; putStrLn ("You said: " ++ line)
    
    main = putStrLn . ("You said: " ++) =&lt;&lt; getLine
    
    

    But unfortunately there are more complicated cases:

    main = do print (True || !getLine == "foo")
    
    

    In a strict language with built-in short-circuiting logical operations the getLine would never be performed, but in Haskell || is just a normal function that happens to be lazy in its second argument. The only reasonable way to implement it seems to be to treat every function as if it was strict and always perform the getLine:

    main = do line &lt;- getLine; print (True || line == "foo")
    
    

    Do you think this is confusing? Or is the bang notation useful enough that you can live with these odd cases? I’m not very happy with this naive desugaring.