News for hackers. Stuff that matters.

suzuki

Re:When to use generics on Wednesday April 13, 2022 @07:46AM (#31013523)
> If you have an interface with a single method, or something with a single varying piece of behavior, please strongly consider accepting a function instead.

Agreed. And if you prefer methods to functions, you can define methods on such a function type! In my LINQ in Go (https://github.com/nukata/linq-in-go), I define a higher order function type:

  type Enumerator[T any] func(yield func(element T))
and several methods on it, for example,

  // Where creates an Enumerator which selects elements by appling
  // predicate to each of them.
  func (loop Enumerator[T]) Where(predicate func(T) bool) Enumerator[T] {
        return func(yield func(T)) {
                loop(func(element T) {
                        if predicate(element) {
                                yield(element)
                        }
                })
        }
  }
Naturally, if you need another type parameter for a method, you must define it as a function. For example,

  // Select creates an Enumerator which applies f to each of elements.
  func Select[T any, R any](f func(T) R, loop Enumerator[T]) Enumerator[R] {
        return func(yield func(R)) {
                loop(func(element T) {
                        value := f(element)
                        yield(value)
                })
        }
  }
Now, with the function which converts a slice to an Enumerator,

  // From creates an Enumerator from a slice.
  func From[T ~[]E, E any](x T) Enumerator[E] {
        return func(yield func(E)) {
                for _, element := range x {
                        yield(element)
                }
        }
  }
you can write the following:

  seq := Select(func(e int) int { return e + 100 },
        From([]int{
                7, 8, 9,
        })).Where(func(e int) bool {
        return e%2 != 0
  })
  seq(func(e int) {
        Println(e)
  })
  // Output:
  // 107
  // 109
Re:Strand Programming Language on Thursday April 29, 2021 @03:34AM (#26978376)
It is a "mojibake" of 三個和尚沒水喝[1].

[1] https://en.wikipedia.org/wiki/Three_Monks

Re:Pip has dropped support for Python 2 on Monday January 25, 2021 @12:09PM (#25905730)
From a Japanese perspective, it also sounds very unlikely. Go with UTF-8 strings is successful nowadays in Japan.
Re:Pip has dropped support for Python 2 on Monday January 25, 2021 @11:35AM (#25905131)
I agree with you. I wish Python 3 had strings as byte sequences mainly in UTF-8 as Python 2 had once and Go has now. Then things would be kept simple in Japan. Python 3 feels cumbersome. To handle a raw input as a string, you must decode it in some encoding first. It is a fragile process. It would be adequate to treat the input bytes transparently and put an optional stage to convert other encodings to UTF-8 if necessary.
Re:Switch from Ruby to Crystal on Friday November 06, 2020 @07:15AM (#25007065)
I have written almost the identical Scheme interpreters in Ruby and Crystal: [1] and [2]. The biggest difference I have felt between them is the absence of good old Object, which can represent everything at runtime, from Crystal. I had to declare Obj and Val:

  class Obj
  end

  # Value operated by Scheme
  alias Val = Nil | Obj | Bool | String | Int32 | Float64 | BigInt
to define Cons Cell of Scheme:

  # Cons cell
  class Cell < Obj
    include Enumerable(Val)

    getter car : Val            # Head part of the cell
    property cdr : Val          # Tail part of the cell

    def initialize(@car : Val, @cdr : Val)
    end

    ...
  end # Cell
Note that you see generics, Enumerable(Val), and constructor arguments with '@' in the excerpt above.

As for performance, Crystal is faster than Ruby 8.6 times as interpreter and 39.4 times as compiler [3]. You can use Crystal as a superfast (and typed) Ruby interpreter, in a sense.

[1] https://github.com/nukata/little-scheme-in-ruby [2] https://github.com/nukata/little-scheme-in-crystal [3] https://github.com/nukata/little-scheme#performance

Re:Statement Regarding the Zen Programming Language on Saturday September 19, 2020 @04:50PM (#24530235)
IANAL, but I believe you cannot put "(c) Your Name 2020" on Shakespeare's works in Japan and other countries. Their copyright acts protect the moral rights of authors[1][2]. So I think Zen's file headers would be violating the law in Japan and other countries.

[1] https://en.wikipedia.org/wiki/Moral_rights [2] http://www.japaneselawtranslation.go.jp/law/detail_main?id=2... (Copyright Act of Japan) Subsection 2 Moral Rights of Authors (Articles 18 to 20)

Re:The Next Step for Generics on Wednesday June 17, 2020 @06:06AM (#23549701)
Now the abstract sequence type of "LINQ in Go" https://github.com/nukata/linq-in-go can be written as

  type Enumerator(type T) func(yield func(element T))
and the "Select" method can be written as

  func (loop Enumerator(T)) Select(f func(T) T) Enumerator(T) {
        return func(yield func(T)) {
                loop(func(element T) {
                        value := f(element)
                        yield(value)
                })
        }
  }
You can call this method with type-safety as follows. Yay!

  func main() {
        squares := Range(1, 3).Select(func(x int) int { return x * x })
        squares(func(num int) {
                fmt.Println(num)
        })
  }
  // Output:
  // 1
  // 4
  // 9
See https://go2goplay.golang.org/p/b0ugT68QAy2 for the complete code.

And, for generality, you should write the method actually as follows.

  func (loop Enumerator(T)) Select(type R)(f func(T) R) Enumerator(R) {
        return func(yield func(R)) {
                loop(func(element T) {
                        value := f(element)
                        yield(value)
                })
        }
  }
However, you will get the error message then:

  type checking failed for main
  prog.go2:17:33: methods cannot have type parameters
According to https://go.googlesource.com/proposal/+/refs/heads/master/des... this seems an intended restriction:

> Although methods of a generic type may use the type's parameters, methods may not themselves have additional type parameters. Where it would be useful to add type arguments to a method, people will have to write a suitably parameterized top-level function.

> This is not a fundamental restriction but it complicates the language specification and the implementation.

For now, we have to write it as https://go2goplay.golang.org/p/mGOx3SWiFXq and I feel it rather inelegant. Good grief

Re:Ruby vs. Crystal Performance on Saturday June 06, 2020 @01:20AM (#23437035)
You are absolutely right. I have written Scheme interpreters in both languages. Compare https://github.com/nukata/little-scheme-in-ruby/blob/v0.3.0/...

  # Cons cell
  class Cell
    include Enumerable
    attr_reader :car
    attr_accessor :cdr

    def initialize(car, cdr)
      @car = car
      @cdr = cdr
    end

    # Yield car, cadr, caddr and so on, à la for-each in Scheme.
    def each
      j = self
      begin
        yield j.car
        j = j.cdr
      end while Cell === j
      j.nil? or raise ImproperListException, j
    end
  end # Cell
and https://github.com/nukata/little-scheme-in-crystal/blob/v0.2...

  # Cons cell
  class Cell < Obj
    include Enumerable(Val)

    getter car : Val            # Head part of the cell
    property cdr : Val          # Tail part of the cell

    def initialize(@car : Val, @cdr : Val)
    end

    # Yield car, cadr, caddr and so on, à la for-each in Scheme.
    def each
      j = self
      loop {
        yield j.as(Cell).car
        j = j.as(Cell).cdr
        break unless Cell === j
      }
      raise ImproperListException.new(j) unless j.nil?
    end
  end # Cell
and they will make the point clear. Ruby and Crystal are different languages, but you can translate your code from Ruby to Crystal line by line fairly easily.

For the performance boost, see https://github.com/nukata/little-scheme/tree/v1.3.0#performa... which shows times to solve 6-Queens on a meta-circular Scheme as follows:

* Crystal 0.34.0: crystal build --release scm.cr: 2.15 sec.

* Crystal 0.34.0: crystal scm.cr: 9.88 sec.

* Ruby 2.3.7: ruby scm.rb: 84.80 sec.

Compiled (and complex enough) Crystal code runs 39 times faster than the equivalent Ruby code in this case.

Re:Python 2.7.18, the last release of Python 2 on Tuesday April 21, 2020 @08:16AM (#22934222)
I totally agree with you. I hope we still have a chance to do it well with PyPy.
Re:Crystal 0.34 on Wednesday April 08, 2020 @02:00AM (#22810436)
I have just updated my Scheme interpreter in Crystal (https://github.com/nukata/little-scheme-in-crystal), which I used on the above benchmark test, along to Crystal 0.34.

The release notes of Crystal 0.34 say "Having as much as possible portable code is part of the goal of the std-lib. One of the areas that were in need of polishing was how Errno and WinError were handled. The Errno and WinError exceptions are now gone, and were replaced by a new hierarchy of exceptions." So I have modified

    rescue ex: Errno
      raise ErrorException.new(ex.message, NONE) if ex.errno == Errno::EPIPE
to

    rescue ex: IO::Error
      raise ErrorException.new(ex.message, NONE) if ex.os_error == Errno::EPIPE
though it is still dependent on POSIX. >_<
Re:Crystal 0.34 on Tuesday April 07, 2020 @11:34AM (#22804146)
Crystal is comparable to Java in performance. I am impressed with it. See https://github.com/nukata/little-scheme#performance and https://github.com/nukata/little-scheme#performance-on-the-t...
Re:Towards Crystal 1.0 on Tuesday March 31, 2020 @08:12AM (#22736748)
In my experiment, the Crystal version (https://github.com/nukata/little-scheme-in-crystal) was 38x faster than the Ruby version (https://github.com/nukata/little-scheme-in-ruby) and comparable to the Java version (https://github.com/nukata/little-scheme-in-java). Indeed, it is in the fastest group. See https://github.com/nukata/little-scheme#performance
I timed each implementation in solving 6-Queens[1] on a meta-circular Scheme[2] (i.e. each Scheme interpreter ran a meta-circular Scheme interpreter to solve 6-Queens). Results are shown in [3]; the order of speed is observed as follows:

Go ≈ Java ≈ Crystal(Compiled) ≈ SBCL > C# ≈ PyPy > TypeScript(Node.js) ≈ Crystal ≈ Dart >> PHP > Python ≈ Ruby

[1] https://github.com/nukata/little-scheme/blob/v1.2.0/examples... [2] https://github.com/nukata/little-scheme/blob/v1.2.0/scm.scm [3] https://github.com/nukata/little-scheme/tree/v1.2.0#performa...

Re:Loopless Programming on Thursday October 24, 2019 @09:44AM (#21344596)
Good point! I'm looking forward to generics in Go.
Re:Loopless Programming on Monday October 21, 2019 @09:09AM (#21311820)
You can write your own LINQ in Go with a very short program. See https://github.com/nukata/linq-in-go for example.

Here is a self-contained excerpt:

  type Any = interface{}

  type Enumerator func(yield func(element Any))

  // Select creates an Enumerator which applies f to each of elements.
  func (loop Enumerator) Select(f func(Any) Any) Enumerator {
    return func(yield func(Any)) {
      loop(func(element Any) {
        value := f(element)
        yield(value)
      })
    }
  }

  // Range creates an Enumerator which counts from start
  // up to start + count - 1.
  func Range(start, count int) Enumerator {
    end := start + count
    return func(yield func(Any)) {
      for i := start; i < end; i++ {
        yield(i)
      }
    }
  }
Now you can write the following:

  squares := Range(1, 10).Select(func(x Any) Any { return x.(int) * x.(int) })
  squares(func(num Any) {
    Println(num)
  })
  // Output:
  // 1
  // 4
  // 9
  // 16
  // 25
  // 36
  // 49
  // 64
  // 81
  // 100
I'd say it is so elegant in Go!
This is a small interpreter of a subset of Scheme. It implements the same language as https://github.com/nukata/little-scheme-in-python (and also its meta-circular interpreter, https://github.com/nukata/little-scheme). As a Scheme implementation, it also handles first-class continuations and runs the yin-yang puzzle correctly.

  $ cat yin-yang-puzzle.scm
  ;; The yin-yang puzzle 
  ;; cf. https://en.wikipedia.org/wiki/Call-with-current-continuation
  
  ((lambda (yin)
     ((lambda (yang)
        (yin yang))
      ((lambda (cc)
         (display '*)
         cc)
       (call/cc (lambda (c) c)))))
   ((lambda (cc)
      (newline)
      cc)
    (call/cc (lambda (c) c))))
  
  ;; => \n*\n**\n***\n****\n*****\n******\n...
  $ little-scheme-in-go yin-yang-puzzle.scm | head
  
  *
  **
  ***
  ****
  *****
  ******
  *******
  ********
  *********
  $
Re:Show HN: An Experimental 'LINQ to Objects' in Go on Friday January 04, 2019 @09:09AM (#18824107)
This LINQ implementation is unique in that it is not related to any particular data structure.

The LINQ code in C# found at https://docs.microsoft.com/dotnet/api/system.linq.enumerable... can be written in Go with this implementation as follows:

  // Generate a sequence of integers from 1 to 10 and then select their squares.
  squares := Range(1, 10).Select(func(x Any) Any { return x.(int) * x.(int) })
  squares(func(num Any) {
      fmt.Println(num)
  })
Here the function Range is defined as follows:

  // Range creates an Enumerator which counts from start
  // up to start + count - 1.
  func Range(start, count int) Enumerator {
      end := start + count
      return func(yield func(Any)) {
          for i := start; i < end; i++ {
              yield(i)
          }
      }
  }
Note that Enumerator is just a function type defined as func(func(Any)). The space complexity is O(1) and you can yield values infinitely if you want.
Re:Windows file access performance compared to Linux on Sunday December 30, 2018 @11:38AM (#18789920)
If you had used WSLGit (https://github.com/andy-5/wslgit), you could use Cyg-Git (https://github.com/nukata/cyg-git) instead. It provides a "Git for Windows" virtually for Go and VSCode. You only need Cygwin and its packages, including Cygwin's git.
Re:Show HN: A Lisp interpreter in C# 7 on Monday July 02, 2018 @07:22AM (#17440746)
Thank you. I appreciated especially the pattern matching feature of C# 7 while programming the interpreter. For example:

        /// <summary>Evaluate a Lisp expression in an environment.</summary>
        public object Eval(object x, Cell env) {
            try {
                for (;;) {
                    switch (x) {
                    case Arg xarg:
                        return xarg.GetValue(env);
                    case Sym xsym:
                        try {
                            return Globals[xsym];
                        } catch (KeyNotFoundException) {
                            throw new EvalException("void variable", x);
                        }
                    case Cell xcell:
Re:Show HN: A Lisp interpreter in C# 7 on Monday July 02, 2018 @07:12AM (#17440705)
Thank you. This Lisp is a translation of my other Lisp in 1200 lines of Dart (https://github.com/nukata/lisp-in-dart), which is, in turn, a digest or refinement of my old L2Lisp in Java (https://github.com/nukata/l2lisp-in-java). I did my best to optimize it for C# 7.
Re:Show HN: A Lisp interpreter in C# 7 on Sunday July 01, 2018 @02:26AM (#17434383)
I wonder if it might be unfair to include the byte-compiled results (with .fast and .elc files) of CLISP and Emacs Lisp to the table.

Older »