Efficient way to implement Towers of Hanoi with steps returned as string - go

I'm comparing several algorithms in JS, Rust and Go. I implemented Towsers of Hanoi this way in Go:
func Hanoi() (hanoi func(n int, from, via, to string) string) {
var moves strings.Builder
var hanoiRe func(n int, from, via, to string)
hanoiRe = func(n int, from, via, to string) {
if n > 0 {
hanoiRe(n-1, from, to, via)
moves.WriteString(from)
moves.WriteString("->")
moves.WriteString(to)
moves.WriteString("\n")
hanoiRe(n-1, via, from, to)
}
}
hanoi = func(n int, from, via, to string) string {
hanoiRe(n, from, via, to)
return moves.String()
}
return
}
But this implementation is much slower than JS or Rust. So I think, this could be done faster. But how?
I already tried type hanoi struct{moves strings.Builder} with func (h *hanoi) ..., which is a bit slower. The way using a string and moves += ...is much slower.
EDIT:
My comparisons:
JS:
class HanoiJS {
constructor() {
this.moves = "";
}
hanoi(n, from, via, to) {
if (n > 0) {
this.hanoi(n - 1, from, to, via);
this.moves += from + "->" + to + "\n";
this.hanoi(n - 1, via, from, to);
}
return this.moves;
}
}
Rust:
pub struct Hanoi {
moves: String
}
impl Hanoi {
pub fn new() -> Hanoi {
Hanoi {
moves: String::new()
}
}
pub fn hanoi(&mut self, n: i32, from: &str, via: &str, to: &str) -> &str {
if n > 0 {
self.hanoi(n - 1, from, to, via);
self.moves.push_str(from);
self.moves.push_str("->");
self.moves.push_str(to);
self.moves.push_str("\n");
self.hanoi(n - 1, via, from, to);
}
return &self.moves;
}
}
Compared with n=20 and 5 times:

Related

Approximating structural typing in a Golang function

A library is providing me a series of types like this:
type T1 struct {
n int
}
type T2 struct {
n int
}
type T3 struct {
n int
}
there is a marker interface like this
type S interface {
isS()
}
func (T1) isS() {}
func (T2) isS() {}
func (T3) isS() {}
I am trying to write a function:
func getN(s S) int {
return s.n
}
Obviously, that won’t compile, and it shouldn’t.
What I am doing now is
func getN(s S) int {
if t1, ok := s.(T1); ok {
return t1
}
if t2, ok := s.(T2); ok {
return t2
}
...
}
That works, but it unbearably awful. The library adds new T structures fairly often and it’s a disastrous violation of open/closed. Any tolerable language has a facility for this kind of situation; what is Golang’s?
Create a method on the interface that returns the type you are looking for. That will get it to compile correctly.
type S interface {
GetN()
}
func (T1) GetN() int {
// impl
}
func (T2) GetN() int {
// impl
}
func (T3) GetN() int {
// impl
}
then if you still need your interesting function that takes an interface, you can do this:
func getN(s S) int {
return s.GetN()
}

How to implement a generic Either type in Go?

With the new generics in Go 1.18, I thought it might be possible to create a 'Either[A,B]' type that can be used to express that something could be either of type A or type B.
A situation where you might use this is in situations where a function might return one of two possible values as a result (e.g. one for 'normal' result and one for an error).
I know the 'idiomatic' Go for errors would be to return both a 'normal' value and an error value, returning a nil for either the error or the value. But... it sort of bothers me that we are essentially saying 'this returns A and B' in the type, where what we really mean to say is 'this returns A or B'.
So I thought maybe we can do better here, and I thought this might also be a good exercise to see/test the boundaries of what we can do with these new generics.
Sadly,try as I might, so far I have not been able solve the exercise and get anything working/compiling. From one of my failed attempts, here is an interface I'd like to implement somehow:
//A value of type `Either[A,B]` holds one value which can be either of type A or type B.
type Either[A any, B any] interface {
// Call either one of two functions depending on whether the value is an A or B
// and return the result.
Switch[R any]( // <=== ERROR: interface methods must have no type parameters
onA func(a A) R),
onB func(b B) R),
) R
}
Unfortunately, this fails rather quickly because declaring this interface isn't allowed by Go. Apparantly because 'interface methods must have no type parameters'.
How do we work around this restriction? Or is there simply no way to create a 'type' in Go that accurately expresses the idea that 'this thing is/returns either A or B' (as opposed to a tuple of both A and B).
If I had to do this, I would look up a functional programming language(like OCaml) and knock-off their solution of the either type..
package main
import (
"errors"
"fmt"
"os"
)
type Optional[T any] interface {
get() (T, error)
}
type None[T any] struct {
}
func (None[T]) get() (T, error) {
var data T
return data, errors.New("No data present in None")
}
type Some[T any] struct {
data T
}
func (s Some[T]) get() (T, error) {
return s.data, nil
}
func CreateNone[T any]() Optional[T] {
return None[T]{}
}
func CreateSome[T any](data T) Optional[T] {
return Some[T]{data}
}
type Either[A, B any] interface {
is_left() bool
is_right() bool
find_left() Optional[A]
find_right() Optional[B]
}
type Left[A, B any] struct {
data A
}
func (l Left[A, B]) is_left() bool {
return true
}
func (l Left[A, B]) is_right() bool {
return false
}
func left[A, B any](data A) Either[A, B] {
return Left[A, B]{data}
}
func (l Left[A, B]) find_left() Optional[A] {
return CreateSome(l.data)
}
func (l Left[A, B]) find_right() Optional[B] {
return CreateNone[B]()
}
type Right[A, B any] struct {
data B
}
func (r Right[A, B]) is_left() bool {
return false
}
func (r Right[A, B]) is_right() bool {
return true
}
func right[A, B any](data B) Either[A, B] {
return Right[A, B]{data}
}
func (r Right[A, B]) find_left() Optional[A] {
return CreateNone[A]()
}
func (r Right[A, B]) find_right() Optional[B] {
return CreateSome(r.data)
}
func main() {
var e1 Either[int, string] = left[int, string](4143)
var e2 Either[int, string] = right[int, string]("G4143")
fmt.Println(e1)
fmt.Println(e2)
if e1.is_left() {
if l, err := e1.find_left().get(); err == nil {
fmt.Printf("The int is: %d\n", l)
} else {
fmt.Fprintln(os.Stderr, err)
}
}
if e2.is_right() {
if r, err := e2.find_right().get(); err == nil {
fmt.Printf("The string is: %s\n", r)
} else {
fmt.Fprintln(os.Stderr, err)
}
}
}
The Either could be modeled as a struct type with one unexported field of type any/interface{}. The type parameters would be used to ensure some degree of compile-time type safety:
type Either[A, B any] struct {
value any
}
func (e *Either[A,B]) SetA(a A) {
e.value = a
}
func (e *Either[A,B]) SetB(b B) {
e.value = b
}
func (e *Either[A,B]) IsA() bool {
_, ok := e.value.(A)
return ok
}
func (e *Either[A,B]) IsB() bool {
_, ok := e.value.(B)
return ok
}
If Switch has to be declared as a method, it can't be parametrized in R by itself. The additional type parameter must be declared on the type definition, however this might make usage a bit cumbersome because then R must be chosen upon instantiation.
A standalone function seems better — in the same package, to access the unexported field:
func Switch[A,B,R any](e *Either[A,B], onA func(A) R, onB func(B) R) R {
switch v := e.value.(type) {
case A:
return onA(v)
case B:
return onB(v)
}
}
A playground with some code and usage: https://go.dev/play/p/g-NmE4KZVq2
You can use the https://github.com/samber/mo library (disclaimer: I'm the project author).
Either signature is:
type Either[L any, R any] struct {}
Some examples:
import "github.com/samber/mo"
left := lo.Left[string, int]("hello")
left.LeftOrElse("world")
// hello
left.RightOrElse(1234)
// 1234
left.IsLeft()
// true
left.IsRight()
// false
Your question about a Switch pattern can be implemented this way:
import "github.com/samber/mo"
left := lo.Left[string, int]("hello")
result := left.Match(
func(s string) Either[string, int] {
// <-- should enter here
return lo.Right[string, int](1234)
},
func(i int) Either[string, int] {
// <-- should not enter here
return lo.Right[string, int](i * 42)
},
)
result.LeftOrElse("world")
// world
result.RightOrElse(42)
// 1234
A solution finally came to me. The key was defining the 'Either' type as a 'struct' instead of an interface.
type Either[A any, B any] struct {
isA bool
a A
b B
}
func Switch[A any, B any, R any](either Either[A, B],
onA func(a A) R,
onB func(b B) R,
) R {
if either.isA {
return onA(either.a)
} else {
return onB(either.b)
}
}
func MakeA[A any, B any](a A) Either[A, B] {
var result Either[A, B]
result.isA = true
result.a = a
return result
}
func MakeB[A any, B any](b B) Either[A, B] {
... similar to MakeA...
}
That works, but at the 'price' of really still using a 'tuple-like' implementation under the hood were we store both an A and a B but ensure it is only possible to use one of them via the public API.
I suspect this is the best we can do given the restrictions Go puts on us.
If someone has a 'workaround' that doesn't essentially use 'tuples' to represent 'unions'. I would consider that a better answer.

Go, first class functions, and best practices

For the past few days, I've been at a road block with regards to the best way to approach the issue of first class functions (assigning a callable to some variable), and the best practices in terms of efficiency.
Let's say I am programming a Yugioh card game, and I want each individual card of type card to have at least these attributes:
type card struct {
name string
text string
}
I have been struggling with the idea on where (and how) to program each card's individual functionality. I am currently convinced that the best place for the first-class function is in type card struct and create the new attribute as a "callable" like I would in Python (Go playground link).
package main
import "fmt"
type card struct {
name string
text string
f interface{}
}
type monsterCard struct {
card
attack int
defense int
}
type buff func(target *monsterCard) // Could be defined in a second file
type swap func(target *monsterCard, value int) // ditto
var increaseAttack buff = func(target *monsterCard) { // ditto
target.attack += 100
}
var swichStats swap = func(target *monsterCard, value int) { // ditto
attack := target.attack
target.attack = value
target.defense = attack
}
func main() {
m1 := monsterCard{
card: card{
name: "Celtic Guardian",
f: increaseAttack,
},
attack: 1400,
defense: 1200,
}
m2 := monsterCard{
card: card{
name: "Dark Magician",
f: swichStats,
},
attack: 2500,
defense: 2100,
}
var monsters = [2]monsterCard{m1, m2}
for _, m := range monsters {
fmt.Println(m)
switch m.f.(type) {
case buff:
m.f.(buff)(&m)
case swap:
m.f.(swap)(&m, m.defense)
default:
fmt.Printf("%T", m.f)
}
fmt.Println(m)
}
}
I'm not very good with regards to efficient code, and I completely understand I might be optimizing early here; however, I will need to program hundreds of these cards, and if having these callables exist in global scope with a heavy reliance on type assertion make the program slow, then I'll be in trouble reorganizing the code.
Are there any glaring issues that you can see with my methodology? Am I going about first-class functions correctly, or is there some kind of glaring performance issues I can't see? Any and all help will be greatly appreciated!
You can use plain functions, and closures where needed:
type card struct {
name string
text string
fn func(*monsterCard)
}
type monsterCard struct {
card
attack int
defense int
}
func (mc *monsterCard) call() {
mc.fn(mc)
}
func increaseAttack(mc *monsterCard) {
mc.attack += 100
}
func switchStats(mc *monsterCard) {
mc.attack, mc.defense = mc.defense, mc.attack
}
func updateTextAndAttack(text string, attack int) func(mc *monsterCard) {
return func(mc *monsterCard) {
mc.text, mc.attack = text, attack
}
}
https://play.golang.com/p/v_RbObnu7sN
You can also use plain methods, and closures where needed:
type card struct {
name string
text string
}
type monsterCard struct {
card
attack int
defense int
}
func (mc *monsterCard) increaseAttack() {
mc.attack += 100
}
func (mc *monsterCard) switchStats() {
mc.attack, mc.defense = mc.defense, mc.attack
}
func (mc *monsterCard) updateTextAndAttack(text string, attack int) func() {
return func() {
mc.text, mc.attack = text, attack
}
}
https://play.golang.com/p/Eo1mm-seldA
Thank you to everyone who helped me through to this answer. It would appear that I'm still using my scripting language mindset to try and solve problems in a compiled language. Instead of trying to create interfaces that ultimately lead to harder to read code, I will need to be more strict in my custom type definitions and implement a different function type for each type of card effect. Such strict enforcement will also allow for cards with multiple effects to exist in the game.
package main
type card struct {
name string
text string
}
type monsterCard struct {
card
attack int
defense int
}
type buffEffect struct {
monsterCard
fn buff
}
type setValueEffect struct {
monsterCard
fn swap
}
type buff func(target *monsterCard)
type swap func(target *monsterCard, value int)
var increaseAttack buff = func(target *monsterCard) {
target.attack += 100
}
var setAttackValue swap = func(target *monsterCard, value int) {
target.attack = value
}
func main() {
m1 := buffEffect{
monsterCard: monsterCard{
card: card{
name: "Celtic Guardian",
},
attack: 1400,
defense: 1200,
},
fn: increaseAttack,
}
m2 := setValueEffect{
monsterCard: monsterCard{
card: card{
name: "Dark Magician",
},
attack: 2500,
defense: 2100,
},
fn: setAttackValue,
}
m1.fn(&m1.monsterCard)
m2.fn(&m2.monsterCard, 100)
}

Generating Go method set with reflection

Is it possible to generate an interface or method set of a struct at runtime with reflection?
For example:
type S struct {
a int
}
func (s *S) Fn(b int) int {
return s.a + b
}
type I interface {
Fn(a int) int
}
func main() {
var x I = &S{a: 5}
fmt.Printf("%#v\n", x.Fn)
fmt.Printf("%#v\n", reflect.TypeOf(x).Method(0))
var y I
y.Fn = x.Fn // This fails, but I want to set y.Fn at runtime.
fmt.Printf("%#v\n", reflect.TypeOf(y).Method(0))
}
https://play.golang.org/p/agH2fQ4tZ_
To clarify, I'm trying to build a middleware library so interface I contains the http handlers and I want to wrap each hander with some sort of req/response logging so I need to return a new interface I where each function in new Interface I wraps the original + some logging.
Here's how to handle this for interfaces I and J.
type I interface { Fn1(a int) int }
type J interface { Fn2(a int) int }
type Y struct { // Y implements I by calling fn
fn func(a int) int
}
func (y Y) Fn1(a int) int { return y.fn(a) }
type Z struct { // Z implements J by calling fn
fn func(a int) int
}
func (z Z) Fn2(a int) int { return y.fn(a) }
var y I = Y{fn: x.Fn}
var z J = Z{fn: x.Fn}
There's no need to use reflection.
playground example

Prototyping struct in Go

My use case is, I need to have several structs in Go, who will have methods of same signatures and not necessarily have to have all the methods. The following code describes the requirements and also represents my current solution.
type calc struct {
fn func(a, b int) int
gn func(a string) bool
name string
}
func add(a, b int) int {
return a + b
}
func bar(foo string) bool {
// do something
}
func sub(a, b int) int {
return a - b
}
func main() {
for c := range []calc{{
fn: add,
gn: bar,
name: "addition",
}, {
fn: sub,
name: "subtraction",
}} {
fmt.Printf("%s(10, 15) returned: %d\n", c.name, c.fn(10, 15))
if c.gn != nil {
c.gn(c.name)
}
}
}
My question is how to improve this code? What's the best way to achieve this in Go? Can I achieve a better solution using interface?
Use interfaces.
type Op interface {
Name() string
Do(a, b int) int
}
type Add struct{}
func (Add) Name() string { return "add" }
func (Add) Do(a, b int) int { return a + b }
type Sub struct{}
func (Sub) Name() string { return "sub" }
func (Sub) Do(a, b int) int { return a - b }
Playground: http://play.golang.org/p/LjJt6D0hNF.
EDIT: Since you've edited your question, here is an example of how you could use asserting and interface to a broader interface for your task:
type RevOp interface {
Op
ReverseDo(a, b int) int
}
// ...
func (Add) ReverseDo(a, b int) int { return a - b }
// ...
fmt.Printf("%s(10, 15) returned: %d\n", op.Name(), op.Do(10, 15))
if op, ok := op.(RevOp); ok {
fmt.Printf("reverse of %s(10, 15) returned: %d\n", op.Name(), op.ReverseDo(10, 15))
}
Playground: http://play.golang.org/p/MQ6LlPDcEi.
I've discussed with some people in person and apparently my solution was correct. While it can be rewritten using interface, that's not necessarily an improvement.

Resources