Running a statement only on outermost function of recursion in Golang - go

I have a recursive function and I want one execute some statement only for the outermost call to the function. How do I achieve this functionality?
func fact(n int) int {
if n == 0 {
return 1
}
fact := n * fact(n-1)
if outer_most{
fmt.Printf(strconv.Itoa(n))
}
return fact
}
func main() {
fact(4)
}
This should print only 4

To answer the question itself: if for some reason you really want to run something that is only for outermost func call and don't want to change api, Golang has a runtime lib for that.
You may do it as:
package main
import (
"fmt"
"runtime"
"strconv"
)
func outer_most() bool {
pc:=make([]uintptr,2)
runtime.Callers(2,pc) //skip: 1 - runtime.Caller, 2 - outer_most itself
return runtime.FuncForPC(pc[0])!=runtime.FuncForPC(pc[1]) // test if the caller of the caller is the same func, otherwise it is the outermost
}
func fact(n int) int {
if n == 0 {
return 1
}
fact := n * fact(n-1)
if outer_most() {
fmt.Printf(strconv.Itoa(n))
}
return fact
}
func main() {
fact(4)
}
playground: https://play.golang.org/p/ro1ZOn6yIR7
It is no good practice, but solve the question most straightfowardly.
Note:
Use a global variable is very likely to cause glitches. You need to set it every time you call the func, and if there is concurency, data race would be involved.
And if you are unconfortable with the fact that the extra bool argument get allocated every recursive call (which could be countless time), you may look at #Adrian 's answer or wrap it as a method of a bool.

You could pass something like a depth that gets incremented at each call. Eg:
func fact(depth int, n int) int {
if n == 0 {
return 1
}
fact := n * fact(depth + 1, n-1)
if depth == 0 {
fmt.Println(fact) // I assume you meant to print fact here.
}
return fact
}
func main() {
fact(0, 4)
}
If this is really your use case, you're much better off doing:
func fact(n int) int {
if n == 0 {
return 1
}
return n * fact(n-1)
}
func main() {
fmt.Println(fact(4))
}

Answer to edited question:
You can use he second pattern below again:
func fact(n int, outerMost bool) int {
if n == 0 {
return 1
}
fact := n * fact(n-1, false)
if outerMost {
fmt.Printf(strconv.Itoa(n))
}
return fact
}
func main() {
fact(4, true)
}
Again, you can use closures or helper functions to clean this up.
Original answer:
Try using a global variable:
var outerMost bool = true
func fact(n int) int {
if outerMost {
fmt.Printf(strconv.Itoa(n))
outerMost = false
}
if n == 0 {
return 1
}
return n * fact(n-1)
}
func main() {
fact(4)
}
There are other ways to achieve this. For example, you can use similar technique with closures as well. Or add another parameter to fact:
func fact(n int, outerMost bool) int {
if outerMost {
fmt.Printf(strconv.Itoa(n))
outerMost = false
}
if n == 0 {
return 1
}
return n * fact(n-1, outerMost)
}
func main() {
fact(4, true)
}

A simple anonymous function is probably the cleanest, as it does not add a parameter, complicating the API for external callers just to implement internal logic.
func fact(n int) int {
var facto func(n int) int
facto = func(n int) int {
if n == 0 {
return 1
}
fact := n * facto(n-1)
return fact
}
n = facto(n)
fmt.Printf("%d", n)
return n
}
This achieves the same functionality, but the caller doesn't have to know to pass an additional bool or int value that's irrelevant to it. Full example here: https://play.golang.org/p/7vHwPDN2_FL

Related

Explain:function returns same function in go

func main() {
go spinner(100 * time.Millisecond)
const n = 45
fibN := fib(n) // slow
fmt.Printf("\rFibonacci(%d) = %d\n", n, fibN)
}
func spinner(delay time.Duration) {
for {
for _, r := range `-\|/` {
fmt.Printf("\r%c", r)
time.Sleep(delay)
}
}
}
func fib(x int) int {
if x < 2 {
return x
}
return fib(x-1) + fib(x-2)
}
can you explain above fib function ,how the results are obtained.
fib function return a fib calls ,how does the end results come?
The key is in this function:
func fib(x int) int {
if x < 2 {
return x
}
return fib(x-1) + fib(x-2)
}
If x<2 the function returns immediately, if not it retrieves the result from a call to fib with a smaller value of x
For recursive calls there are the 3 Laws of Recursion:
A recursive algorithm must have a base case.
A recursive algorithm
must change its state and move toward the base case.
A recursive
algorithm must call itself, recursively.
http://interactivepython.org/courselib/static/pythonds/Recursion/TheThreeLawsofRecursion.html
In your example, the base case is when x < 2. The state change is the reduction by 1 or 2 and your function calls itself recursively so the three laws are met.

communicating with n goroutines

I am trying to implement fibonacci recursion in golang using n goroutines with communicating via channels.
I am returning an integer from the function, but i am actually just sending the sum of f(n-1) +f(n-2) over channel c but this is not working correctly. It prints the first two values correct, and every value after is just 1.
package main
import "fmt"
// Fibonacci in a recursive version
func fiboR(n int, c chan int ) int {
if(n == 0){
c <- 0
return 0
} else if n == 1 {
c <- 1
return 1
} else{
c <- fiboR(n-1,c) + fiboR(n-2,c)
return fiboR(n-1,c) + fiboR(n-2,c)
}
}
func main() {
for i := 0; i < 10; i++ {
procchan := make(chan int)
go fiboR(i,procchan)
fmt.Println(i,<-procchan )
}
}
Also is it possible to use channels for receiving the two recursive calls?
Your solution will try to output more than the one value you extract from the channel as you increase the value of i.
What your code will try to send to the channel for each i:
0: 0
1: 1
2: 1,0,1
3: 1,0,1,1,2
4: 1,0,1,1,2,1,0,1,3
...
Since you create a new channel for each i and then only extract one value you will always get the first value in the line above.
If you try to run it with these modifications it will output what you wanted (https://play.golang.org/p/_mn3l5x8iZ).
package main
import "fmt"
// Fibonacci in a recursive version
func fiboRchan(n int, c chan int) {
c <- fiboR(n)
}
func fiboR(n int) int {
if n == 0 {
return 0
} else if n == 1 {
return 1
} else {
return fiboR(n-1) + fiboR(n-2)
}
}
func main() {
for i := 0; i < 10; i++ {
procchan := make(chan int)
go fiboRchan(i, procchan)
fmt.Println(i, <-procchan)
}
}
Adding to #nissefors answer, the main process there is most likely a sequential one because in the for loop you would be waiting on the channel to return and then proceed to the next iteration.
A minor modification in the main function could fire all the fibonaccis at once and then in a separate for loop the channels that are corresponding to each go routine can be accessed
Playground URL: https://play.golang.org/p/7e3JnWeSp6
package main
import "fmt"
// Fibonacci in a recursive version
func fiboRchan(n int, c chan int) {
fmt.Println("PROCESSING FOR %d", n)
c <- fiboR(n)
}
func fiboR(n int) int {
if n == 0 {
return 0
} else if n == 1 {
return 1
} else {
return fiboR(n-1) + fiboR(n-2)
}
}
func main() {
var arr[10]chan int
for i := 0; i < 10; i++ {
procchan := make(chan int)
arr[i] = procchan
go fiboRchan(i, procchan)
}
// By now all the go routines are fired
// Now iterate through the channel array and read from the
// respective channel
for i:=0; i< 10; i++ {
fmt.Println(i, <-arr[i])
}
}

get sum of bigInt number golang

Hi i am new to the golang programming language. I can get the bigint
value from the factoral function but it is not working with the add
function.
i have had the add function accepting bigint but when i try to add a
.Mod and .Div methods it returns 0 fro some reason. the if else
statement in the add function is an old statement i was using when i
had int values coming from the factoral function.
it worked perfectly when it was as int value. When i attempted to
alter the if else statement to accept bigint values i couldn't get it
to work at all.
I have tried the .Mod and .Div methods and they are printing out the
correct values. But when i try to .Add them together it always returns
0. even if the values are "22", "2". I've put the if else statement back to the original int values for now.
if anyone can help me out with this one i would be very greatful.
package main
import (
"fmt"
"math/big"
)
func factoral(n uint64) (r *big.Int) {
one, bn := big.NewInt(1), new(big.Int).SetUint64(n)
r = big.NewInt(1)
if bn.Cmp(one) <= 0 {
return
}
for i := big.NewInt(2); i.Cmp(bn) <= 0; i.Add(i, one) {
r.Mul(r, i)
}
return
}
func add(number *big.Int) *big.Int {
//this the statement that works with normal int values
if number/10 < 10 {
return sum + number/10
} else {
return sum + add(number/10)
}
}
func main() {
fmt.Println(add(factoral(100)))
}
Fixed it
package main
import (
"fmt"
"math/big"
)
func factoral(n uint64) (r *big.Int) {
one, bn := big.NewInt(1), new(big.Int).SetUint64(n)
r = big.NewInt(1)
if bn.Cmp(one) <= 0 {
return
}
for i := big.NewInt(2); i.Cmp(bn) <= 0; i.Add(i, one) {
r.Mul(r, i)
}
return
}
func add(number *big.Int) *big.Int {
ten := big.NewInt(10)
sum := big.NewInt(0)
mod := big.NewInt(0)
for ten.Cmp(number)<0 {
sum.Add(sum, mod.Mod(number,ten))
number.Div(number,ten)
}
sum.Add(sum,number)
return sum
}
func main() {
fmt.Println(add(factoral(100)))
}
Seems your issue was likely with the way the Big Int object whose method you invoke is going to be the one the value is assigned to, and not necessarily one of the arguments.
See: https://golang.org/pkg/math/big/#Int.Div

What is the idiomatic Go equivalent of C's ternary operator?

In C/C++ (and many languages of that family), a common idiom to declare and initialize a variable depending on a condition uses the ternary conditional operator :
int index = val > 0 ? val : -val
Go doesn't have the conditional operator. What is the most idiomatic way to implement the same piece of code as above ? I came to the following solution, but it seems quite verbose
var index int
if val > 0 {
index = val
} else {
index = -val
}
Is there something better ?
As pointed out (and hopefully unsurprisingly), using if+else is indeed the idiomatic way to do conditionals in Go.
In addition to the full blown var+if+else block of code, though, this spelling is also used often:
index := val
if val <= 0 {
index = -val
}
and if you have a block of code that is repetitive enough, such as the equivalent of int value = a <= b ? a : b, you can create a function to hold it:
func min(a, b int) int {
if a <= b {
return a
}
return b
}
...
value := min(a, b)
The compiler will inline such simple functions, so it's fast, more clear, and shorter.
No Go doesn't have a ternary operator. Using if/else syntax is the idiomatic way.
Why does Go not have the ?: operator?
There is no ternary testing operation in Go. You may use the following to achieve the same result:
if expr {
n = trueVal
} else {
n = falseVal
}
The reason ?: is absent from Go is that the language's designers had seen the operation used too often to create impenetrably complex expressions. The if-else form, although longer, is unquestionably clearer. A language needs only one conditional control flow construct.
— Frequently Asked Questions (FAQ) - The Go Programming Language
Suppose you have the following ternary expression (in C):
int a = test ? 1 : 2;
The idiomatic approach in Go would be to simply use an if block:
var a int
if test {
a = 1
} else {
a = 2
}
However, that might not fit your requirements. In my case, I needed an inline expression for a code generation template.
I used an immediately evaluated anonymous function:
a := func() int { if test { return 1 } else { return 2 } }()
This ensures that both branches are not evaluated as well.
The map ternary is easy to read without parentheses:
c := map[bool]int{true: 1, false: 0} [5 > 4]
Foreword: Without arguing that if else is the way to go, we can still play with and find pleasure in language-enabled constructs.
Go 1.18 generics update: Go 1.18 adds generics support. It is now possible to create a generic If() function like this. Note: This is available in github.com/icza/gog, as gog.If() (disclosure: I'm the author).
func If[T any](cond bool, vtrue, vfalse T) T {
if cond {
return vtrue
}
return vfalse
}
Which you can use like this:
min := If(i > 0, i, 0)
The pre-1.18 answer follows:
The following If construct is available in my github.com/icza/gox library with lots of other methods, being the gox.If type.
Go allows to attach methods to any user-defined types, including primitive types such as bool. We can create a custom type having bool as its underlying type, and then with a simple type conversion on the condition, we have access to its methods. Methods that receive and select from the operands.
Something like this:
type If bool
func (c If) Int(a, b int) int {
if c {
return a
}
return b
}
How can we use it?
i := If(condition).Int(val1, val2) // Short variable declaration, i is of type int
|-----------| \
type conversion \---method call
For example a ternary doing max():
i := If(a > b).Int(a, b)
A ternary doing abs():
i := If(a >= 0).Int(a, -a)
This looks cool, it's simple, elegant, and efficient (it's also eligible for inlining).
One downside compared to a "real" ternary operator: it always evaluates all operands.
To achieve deferred and only-if-needed evaluation, the only option is to use functions (either declared functions or methods, or function literals), which are only called when / if needed:
func (c If) Fint(fa, fb func() int) int {
if c {
return fa()
}
return fb()
}
Using it: Let's assume we have these functions to calculate a and b:
func calca() int { return 3 }
func calcb() int { return 4 }
Then:
i := If(someCondition).Fint(calca, calcb)
For example, the condition being current year > 2020:
i := If(time.Now().Year() > 2020).Fint(calca, calcb)
If we want to use function literals:
i := If(time.Now().Year() > 2020).Fint(
func() int { return 3 },
func() int { return 4 },
)
Final note: if you would have functions with different signatures, you could not use them here. In that case you may use a function literal with matching signature to make them still applicable.
For example if calca() and calcb() would have parameters too (besides the return value):
func calca2(x int) int { return 3 }
func calcb2(x int) int { return 4 }
This is how you could use them:
i := If(time.Now().Year() > 2020).Fint(
func() int { return calca2(0) },
func() int { return calcb2(0) },
)
Try these examples on the Go Playground.
func Ternary(statement bool, a, b interface{}) interface{} {
if statement {
return a
}
return b
}
func Abs(n int) int {
return Ternary(n >= 0, n, -n).(int)
}
This will not outperform if/else and requires cast but works. FYI:
BenchmarkAbsTernary-8 100000000 18.8 ns/op
BenchmarkAbsIfElse-8 2000000000 0.27 ns/op
If all your branches make side-effects or are computationally expensive the following would a semantically-preserving refactoring:
index := func() int {
if val > 0 {
return printPositiveAndReturn(val)
} else {
return slowlyReturn(-val) // or slowlyNegate(val)
}
}(); # exactly one branch will be evaluated
with normally no overhead (inlined) and, most importantly, without cluttering your namespace with a helper functions that are only used once (which hampers readability and maintenance). Live Example
Note if you were to naively apply Gustavo's approach:
index := printPositiveAndReturn(val);
if val <= 0 {
index = slowlyReturn(-val); // or slowlyNegate(val)
}
you'd get a program with a different behavior; in case val <= 0 program would print a non-positive value while it should not! (Analogously, if you reversed the branches, you would introduce overhead by calling a slow function unnecessarily.)
As others have noted, golang does not have a ternary operator or any equivalent. This is a deliberate decision thought to improve readability.
This recently lead me to a scenario where constructing a bit-mask in a very efficient manner became hard to read when written idiomatically, or very inefficient when encapsulated as a function, or both, as the code produces branches:
package lib
func maskIfTrue(mask uint64, predicate bool) uint64 {
if predicate {
return mask
}
return 0
}
producing:
text "".maskIfTrue(SB), NOSPLIT|ABIInternal, $0-24
funcdata $0, gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB)
funcdata $1, gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB)
movblzx "".predicate+16(SP), AX
testb AL, AL
jeq maskIfTrue_pc20
movq "".mask+8(SP), AX
movq AX, "".~r2+24(SP)
ret
maskIfTrue_pc20:
movq $0, "".~r2+24(SP)
ret
What I learned from this was to leverage a little more Go; using a named result in the function (result int) saves me a line declaring it in the function (and you can do the same with captures), but the compiler also recognizes this idiom (only assign a value IF) and replaces it - if possible - with a conditional instruction.
func zeroOrOne(predicate bool) (result int) {
if predicate {
result = 1
}
return
}
producing a branch-free result:
movblzx "".predicate+8(SP), AX
movq AX, "".result+16(SP)
ret
which go then freely inlines.
package lib
func zeroOrOne(predicate bool) (result int) {
if predicate {
result = 1
}
return
}
type Vendor1 struct {
Property1 int
Property2 float32
Property3 bool
}
// Vendor2 bit positions.
const (
Property1Bit = 2
Property2Bit = 3
Property3Bit = 5
)
func Convert1To2(v1 Vendor1) (result int) {
result |= zeroOrOne(v1.Property1 == 1) << Property1Bit
result |= zeroOrOne(v1.Property2 < 0.0) << Property2Bit
result |= zeroOrOne(v1.Property3) << Property3Bit
return
}
produces https://go.godbolt.org/z/eKbK17
movq "".v1+8(SP), AX
cmpq AX, $1
seteq AL
xorps X0, X0
movss "".v1+16(SP), X1
ucomiss X1, X0
sethi CL
movblzx AL, AX
shlq $2, AX
movblzx CL, CX
shlq $3, CX
orq CX, AX
movblzx "".v1+20(SP), CX
shlq $5, CX
orq AX, CX
movq CX, "".result+24(SP)
ret
eold's answer is interesting and creative, perhaps even clever.
However, it would be recommended to instead do:
var index int
if val > 0 {
index = printPositiveAndReturn(val)
} else {
index = slowlyReturn(-val) // or slowlyNegate(val)
}
Yes, they both compile down to essentially the same assembly, however this code is much more legible than calling an anonymous function just to return a value that could have been written to the variable in the first place.
Basically, simple and clear code is better than creative code.
Additionally, any code using a map literal is not a good idea, because maps are not lightweight at all in Go. Since Go 1.3, random iteration order for small maps is guaranteed, and to enforce this, it's gotten quite a bit less efficient memory-wise for small maps.
As a result, making and removing numerous small maps is both space-consuming and time-consuming. I had a piece of code that used a small map (two or three keys, are likely, but common use case was only one entry) But the code was dog slow. We're talking at least 3 orders of magnitude slower than the same code rewritten to use a dual slice key[index]=>data[index] map. And likely was more. As some operations that were previously taking a couple of minutes to run, started completing in milliseconds.\
One-liners, though shunned by the creators, have their place.
This one solves the lazy evaluation problem by letting you, optionally, pass functions to be evaluated if necessary:
func FullTernary(e bool, a, b interface{}) interface{} {
if e {
if reflect.TypeOf(a).Kind() == reflect.Func {
return a.(func() interface{})()
}
return a
}
if reflect.TypeOf(b).Kind() == reflect.Func {
return b.(func() interface{})()
}
return b
}
func demo() {
a := "hello"
b := func() interface{} { return a + " world" }
c := func() interface{} { return func() string { return "bye" } }
fmt.Println(FullTernary(true, a, b).(string)) // cast shown, but not required
fmt.Println(FullTernary(false, a, b))
fmt.Println(FullTernary(true, b, a))
fmt.Println(FullTernary(false, b, a))
fmt.Println(FullTernary(true, c, nil).(func() string)())
}
Output
hello
hello world
hello world
hello
bye
Functions passed in must return an interface{} to satisfy the internal cast operation.
Depending on the context, you might choose to cast the output to a specific type.
If you wanted to return a function from this, you would need to wrap it as shown with c.
The standalone solution here is also nice, but could be less clear for some uses.
Now with the release of go1.18 generics, it's very easy to do it with a generic function like this, and it is reusable through your whole app
package main
import (
"fmt"
)
func Ternary[T any](condition bool, If, Else T) T {
if condition {
return If
}
return Else
}
func main() {
fmt.Println(Ternary(1 < 2, "yes", "no")) // yes
fmt.Println(Ternary(1 < 2, 1, 0)) // 1
fmt.Println(Ternary[bool](1 < 2, true, false)) // true
}
be aware if you use it in this case it will crash.
in this case, just use an if statement,
(because you passing into the function a nil pointer VS an if statement is not calling that section if it is false)
var a *string
fmt.Println(Ternary(a != nil, *a, "some thing else"))
the solution call it with a function, so it will not be excuted if it's false
func TernaryPointer[T any](condition bool, If, Else func() T) T {
if condition {
return If()
}
return Else()
}
var pString *string
fmt.Println(TernaryPointer(
pString != nil, // condition
func() string { return *pString }, // true
func() string { return "new data" }, // false
))
but in this case, I think a regular if statement is cleaner (except if go adds arrow functions in the future)
playground
give credit for this answer he already answered it
I have compiled some items and compared the speed.
/*
go test ternary_op_test.go -v -bench="^BenchmarkTernaryOperator" -run=none -benchmem
*/
package _test
import (
"testing"
)
func BenchmarkTernaryOperatorIfElse(b *testing.B) {
for i := 0; i < b.N; i++ {
if i%2 == 0 {
_ = i
} else {
_ = -i
}
}
}
// https://stackoverflow.com/a/45886594/9935654
func Ternary(statement bool, a, b interface{}) interface{} {
if statement {
return a
}
return b
}
func BenchmarkTernaryOperatorTernaryFunc(b *testing.B) {
for i := 0; i < b.N; i++ {
_ = Ternary(i%2 == 0, i, -i).(int)
}
}
// https://stackoverflow.com/a/34636594/9935654
func BenchmarkTernaryOperatorWithFunc(b *testing.B) {
for i := 0; i < b.N; i++ {
_ = func() int {
if i%2 == 0 {
return i
} else {
return -i
}
}
}
}
// https://stackoverflow.com/a/31483763/9935654
func BenchmarkTernaryOperatorMap(b *testing.B) {
for i := 0; i < b.N; i++ {
_ = map[bool]int{true: i, false: -i}[i%2 == 0]
}
}
output
goos: windows
goarch: amd64
cpu: Intel(R) Core(TM) i7-8565U CPU # 1.80GHz
BenchmarkTernaryOperatorIfElse
BenchmarkTernaryOperatorIfElse-8 1000000000 0.4460 ns/op 0 B/op 0 allocs/op
BenchmarkTernaryOperatorTernaryFunc
BenchmarkTernaryOperatorTernaryFunc-8 1000000000 0.3602 ns/op 0 B/op 0 allocs/op
BenchmarkTernaryOperatorWithFunc
BenchmarkTernaryOperatorWithFunc-8 659517496 1.642 ns/op 0 B/op 0 allocs/op
BenchmarkTernaryOperatorMap
BenchmarkTernaryOperatorMap-8 13429532 82.48 ns/op 0 B/op 0 allocs/op
PASS
ok command-line-arguments 4.365s
One more suggestion for the idiomatic approach in Go of ternary operator:
package main
import (
"fmt"
)
func main() {
val := -5
index := func (test bool, n, d int) int {
if test {
return n
}
return d
}(val > 0, val, -val)
fmt.Println(index)
}
Go Playground
I was playing with a solution that doesn't use the three arguments function.
Don't take me wrong, the three arguments solution works great but personally i like to name things explicitly.
What i'd love is an explicit interface like that:
When(<condition>).Then(<true value>).Else(<false value>)
I implemented this like that:
type Else[T any] interface {
ElseDo(fn func() T) T
Else(value T) T
}
type Then[T any] interface {
ThenDo(fn func() T) Else[T]
Then(value T) Else[T]
}
type Condition[T any] struct {
condition bool
thenValue T
thenFn func() T
}
func When[T any](condition bool) Then[T] {
return &Condition[T]{condition: condition}
}
func (c *Condition[T]) ThenDo(fn func() T) Else[T] {
c.thenFn = fn
return c
}
func (c *Condition[T]) Then(value T) Else[T] {
c.thenValue = value
return c
}
func (c *Condition[T]) ElseDo(fn func() T) T {
if c.condition {
return c.then()
}
return fn()
}
func (c *Condition[T]) Else(value T) T {
if c.condition {
return c.then()
}
return value
}
func (c *Condition[T]) then() T {
if c.thenFn != nil {
return c.thenFn()
}
return c.thenValue
}
Usage:
When[int](something == "expectedValue").Then(0).Else(1)
When[int](value > 0).Then(value).Else(1)
When[int](value > 0).ThenDo(func()int {return value * 4}).Else(1)
When[string](boolean == true).Then("it is true").Else("it is false")
Unfortunately i didn't find a way to get rid of the explicit type when calling the When function. The type is not automatically inferred by the return types of Then/Else 🤷‍♂️

Idiomatic way of implementing nested matrices in golang

I am trying to represent a hypergraph in memory. Are there any better data structures for this task beside nested matrices? A nested matrix is a matrix which can have elements of both the "native" type (let's say int for the sake of simplicity) and matrices.
This is the beginning of such a matrix. Are there any rough edges in the code, to make it look more idiomatic? How to make it look more idiomatic?
The code:
package main
import "fmt"
type Matricial interface {
Put(interface{}, ...int)
Get(...int) interface{}
}
type Matrix struct {
Matricial
values map[int]interface{}
}
func NewMatrix() *Matrix {
m := &Matrix{}
m.values = make(map[int]interface{})
return m
}
func (m *Matrix) Set(atom interface{}, pos ...int) {
firstdim := pos[0]
if val, ok := m.values[firstdim]; ok {
fmt.Println("map key exists", val)
switch converted := val.(type) {
case int:
m.values[firstdim] = converted
default:
fmt.Println("ERR: unknown type: %T", val)
}
} else {
if len(pos[1:]) > 0 {
newm := NewMatrix()
m.values[firstdim] = newm
newm.Set(atom, pos[1:]...)
} else {
m.values[firstdim] = atom
}
}
}
func (m *Matrix) Get(pos ...int) interface{} {
if len(pos) == 1 {
return m.values[pos[0]]
} else {
switch accessor := m.values[pos[0]].(type) {
case Matricial:
return accessor.Get(pos[1:]...)
default:
return nil
}
}
return nil
}
func main() {
m := NewMatrix()
m.Set(42, 2, 3, 4)
m.Set(43, 0)
fmt.Println(m.Get(2, 3))
fmt.Println(m.Get(2, 3, 4))
fmt.Println(m.Get(0))
}
The data structure must allow connecting hyperedges with other hyperedges (i.e. handling hyperedges as though they were nodes).
A nested matrix (adopting your definition of the term) seems a reasonable representation for hypergraph, not knowing anything more about your application anyway. An example Go implementation is the power set example at Rosetta code.
It is not idiomatic to embed an interface. For example, if you rename the Put method of Matricial to be Set, which is what I think you meant, then you can just delete the Matricial field of Matrix and your program produces the same output.

Resources