Hacker News new | ask | show | jobs
by MatthewPhillips 4699 days ago
Is it possible to write Go in a functional way? Are there first class functions? Anonymous functions? If so it seems it would be possible to write highly functional code given the flexibility of interface{}
6 comments

> Are there first class functions? Anonymous functions?

Yes.

> If so it seems it would be possible to write highly functional code given the flexibility of interface{}

Not really, you'd have to add type assertions everywhere as go has neither generic functions nor user-defined generic types (only a handful of special-status types get to have type parameters, IIRC they're chans, arrays, slices and maps). That makes higher-order operations extremely cumbersome.

I'm also uncertain whether scalars (e.g. integral types) can be used through interface{}.

> I'm also uncertain whether scalars (e.g. integral types) can be used through interface{}.

They can (and there are optimizations to avoid heap allocation in some cases when you do use them), but you still have to write downcasts everywhere.

It is monomorphically typed, however, which limits the use of higher-order functions.
It seems to me that Go is incredibly crappy for writing in a functional style. Have a look at Rust if that's what you're after.
I wrote a library for Go that makes functional programming with channels-as-streams very comfortable, for me[1]. There is a problem with needing to box and unbox variables from the 'empty interface{}' type all the time but it's a minor wart IMO.

It's a really small library that was made in response to my own intuition (similar to yours) that the Go standard library wasn't really embracing a functional style. I haven't used it in any major projects but for small one-off things it's proved pretty useful. It basically works like pipes on the command line.

1: https://github.com/eblume/proto

Up to a point, but go's limited datatypes make it difficult to write the kind of code you're used to writing in haskell/f#/etc.
A haskell version with the Warp server performs just a little bit worse than the go version (6 secs vs 7 secs) with a little bigger minimal latency (68 ms vs 71 ms).

  go version go1.0.2
  runghc 7.6.2
  cabal packages of today
Runned with "runhaskell main.hs" on localhost over loopback :)

  import qualified Network.Wai as Wai
  import qualified Network.Wai.Handler.Warp as Warp
  import qualified Network.HTTP.Types as HTTP
  import qualified Data.ByteString as ByteString
  import Blaze.ByteString.Builder.ByteString (fromByteString)
  
  main = do
      let port = 8000
      Warp.run port app
  
  app req = do
      let n = 1024*1024
      let bytes = fromByteString $ ByteString.replicate n 100
      return $ Wai.ResponseBuilder HTTP.status200 [] bytes
Am I right in thinking that Haskell servers will likely be winning on these benchmarks after Mio is released in 7.8.1? https://news.ycombinator.com/item?id=6198068
Since Warp seems to use many light-weight(green) threads behind the scenes, and Mio is mainly about improving multithreaded performance on actual multi-core set ups, the answer seems to be yes.

However, it would probably only help if you use -threaded (which you should, anyways).

Have you tried precompiling with -O2? IIRC runhaskell runs code like GHCi: interpreted bytecode by default (for source .hs files).
Yes I have and I invite you to do it also by yourself to check it. There is no significant difference in this benchmark between "ghc -O2" and "runhaskell". I didn't investigated why... but I would be very interested in the details :)

Also "-threaded" gives the usual penalty of bookkeeping and bad caching and stuff. You don't need threads in such a benchmark. Though I am mildly surprised that "node" runs faster with multiple processes :)

Don't use "runhaskell", it's more of a "script mode".

Use: ghc -threaded -O2 main.hs && ./main

There is no significant difference in this benchmark. Do you measure something different?
I didn't measure, no.

I suppose maybe it uses the optimized compiled packages code, and the main code doesn't really do anything, so -O2 doesn't matter.

However, I would still expect "-threaded" to have an effect.

Yes, a negative one for this benchmark :)
there are first class functions, and closures work the way you would expect. Since it's statically typed and there are no generics, there's no way to implement something like a left fold; you'd have to implement it on a per-type basis, but you could certainly do that. I believe the answer you're looking for is "no", but Go's functions are nothing to sneeze at. http://jordanorelli.tumblr.com/post/42369331748/function-typ...
> you'd have to implement it on a per-type basis

Alternatively you can implement everything on interface{} and force the user of the higher-order function to use type assertions everywhere.

If you're interested, I did an in depth write up on how to do it. [1]

[1] - http://blog.burntsushi.net/type-parametric-functions-golang