--- /dev/null
+
+package main
+
+import (
+ "fmt"
+ "encoding/json"
+ "reflect"
+)
+
+// Unmarshal json to a struct containing interface field. See full
+// corresponding Haskell code in separate file.
+
+// Haskell:
+// class I a where
+// f :: a -> ()
+type I interface {
+ f()
+}
+
+type S struct {
+ X int
+}
+
+var _ I = S{}
+func (s S) f() {}
+
+// Haskell: data R1 = forall a. I a => R1 a Int
+// I.e. data constructor type is 'R1 :: forall a. I a => a -> Int -> R1',
+// and the type is existential.
+type R1 struct {
+ I I
+ Y int
+}
+
+// Haskell: data R2 a = R2 a Int
+// I.e. data constructor type is 'R2 :: forall a. a -> Int -> R2 a',
+// and this is regular (not existential) type.
+type R2[T any] struct {
+ I T
+ Y int
+}
+
+// Version of 'S' with pointer receiver for use with 'R3'.
+type SP struct {
+ X int
+}
+
+var _ I = (*SP)(nil)
+func (s *SP) f() {}
+
+// Haskell does not have reflect, so there is no equivalent of 'R3'.
+type R3 struct {
+ I I
+ Y int
+}
+
+func (r *R3) UnmarshalJSON(bs []byte) (err error) {
+ v := struct {
+ I json.RawMessage
+ Y int
+ }{}
+
+ err = json.Unmarshal(bs, &v)
+ if err != nil {
+ return
+ }
+ r.Y = v.Y
+
+ if r.I != nil {
+ p := reflect.ValueOf(r.I)
+ if p.Kind() != reflect.Pointer {
+ err = fmt.Errorf("R3.UnmarshalJSON(): Interface 'r.I' uses value receiver '%v'", p.Type())
+ return
+ }
+
+ if err = json.Unmarshal(v.I, p.Interface()); err != nil {
+ return
+ }
+ }
+
+ return
+}
+
+// Haskell:
+// class Read a => I2 a where
+// f2 :: a -> ()
+type I2 interface {
+ f2()
+ json.Unmarshaler
+}
+
+type S2 struct {
+ X int
+}
+
+// Dummy instance, but it's required by 'I2'.
+var _ json.Unmarshaler = (*S2)(nil)
+func (s *S2) UnmarshalJSON(bs []byte) error {
+ v := struct {X int}{}
+ if err := json.Unmarshal(bs, &v); err != nil {
+ return err
+ }
+ s.X = v.X
+ return nil
+}
+
+// Implementing I2 with value receiver has no sense, because
+// 'json.Unmarshaler' can only work with pointer receiver.
+var _ I2 = (*S2)(nil)
+func (s *S2) f2() {}
+
+// Haskell: data R4 = forall a. I2 a => R4 a Int
+// I.e. data constructor is: 'R4 :: forall a. I2 a => a -> Int -> R4'
+type R4 struct {
+ I I2
+ Y int
+}
+
+// json.UnmarshalJSON() method in Go has a pointer to actual data, so it
+// actually does know what type is behind existential interface 'I2'. But
+// Haskell only uses types and does not look at values during type check.
+// Therefore, a function equivalent to 'json.UnmarshalJSON()' should have a
+// type witness, which tell Haskell, which type to use for interface 'I2'. So,
+// the implementation of 'json.Unmarshaler will look like:
+//
+// class Unmarshaler b a where
+// read' :: Proxy a -> String -> b
+//
+// and an instance for R4 will be:
+//
+// instance I2 a => Unmarshaler R4 a where
+
+func main() {
+ jsBytes := []byte(`{"I": {"X": 1}, "Y": 2}`)
+
+ var err error
+
+ r1 := R1{}
+ err = json.Unmarshal(jsBytes, &r1)
+ fmt.Printf("R1: err = %v, r1 = %v\n", err, r1)
+
+ r2 := R2[S]{}
+ err = json.Unmarshal(jsBytes, &r2)
+ fmt.Printf("R2: err = %v, r2 = %v\n", err, r2)
+
+ r3 := R3{I: S{}}
+ err = json.Unmarshal(jsBytes, &r3)
+ fmt.Printf("R3{S}: err = %v, r3 = %v\n", err, r3)
+
+ r3p := R3{I: &SP{}}
+ err = json.Unmarshal(jsBytes, &r3p)
+ fmt.Printf("R3{SP}: err = %v, r3p = %v, r3p.I = %v\n", err, r3p, r3p.I)
+
+ r4 := R4{I: &S2{}}
+ err = json.Unmarshal(jsBytes, &r4)
+ fmt.Printf("R4: err = %v, r4 = %v, r4.I = %v\n", err, r4, r4.I)
+}
--- /dev/null
+{-# LANGUAGE ViewPatterns #-}
+
+import Data.List
+
+-- Here is Haskell equivalent of unmarshaling json to interface in Go. See
+-- corresponding Go file for full Go code.
+
+-- I'll use regular 'Show' and 'Read' instances instead of marshaling to/from
+-- json. 'Show' instance will be required during creation of values of 'Rx'
+-- types. But it's actually does not matter, where to require it or require or
+-- not at all.
+
+-- Go:
+-- type I interface {
+-- f()
+-- }
+class I a where
+ f :: a -> ()
+
+-- Go:
+-- type S struct {
+-- X int
+-- }
+data S = S Int
+ deriving (Show, Read)
+
+-- Go:
+-- var _ I = S{}
+-- func (s S) f() {}
+instance I S where
+ f _ = ()
+
+-- Go:
+-- type R1 struct {
+-- I I
+-- Y int
+-- }
+data R1 = forall a. (I a, Show a) => R1 a Int
+deriving instance Show R1
+-- So data constructor type is: R1 :: forall a. (I a, Show a) => a -> Int -> R1 .
+-- I.e. i can't say what 'a' was used by looking at type 'R1' of some 'x :: R1'.
+-- And therefore 'Read' instance won't typecheck with:
+--
+-- Ambiguous type variable ‘a0’ arising from a use of
+-- ‘GHC.Read.readPrec’ prevents the constraint ‘(Read a0)’ from being
+-- solved.
+--
+--deriving instance Read R1
+
+-- Go:
+-- type R2[T any] struct {
+-- I T
+-- Y int
+-- }
+data R2 a = R2 a Int
+ deriving (Show, Read)
+
+-- Go:
+-- type I2 interface {
+-- f2()
+-- json.Unmarshaler
+-- }
+class Read a => I2 a where
+ f2 :: a -> ()
+
+data S2 = S2 Int
+ deriving (Show, Read)
+
+instance I2 S2 where
+ f2 _ = ()
+
+-- Go:
+-- type R4 struct {
+-- I I2
+-- Y int
+-- }
+data R4 = forall a. (I2 a, Show a) => R4 a Int
+deriving instance Show R4
+-- So data constructor type is: R4 :: forall a. (I2 a, Show a) => a -> Int -> R4 ,
+-- which means, that by looking at value type R4 i can't say what type 'a' to
+-- use. Therefore, 'Read' instance can't be written
+--
+-- Ambiguous type variable ‘a0’ arising from a use of ‘R4’
+-- prevents the constraint ‘(I2 a0)’ from being solved.
+--
+--deriving instance Read R4
+
+-- But Go's 'json.Unmarshaler' interface works differently: it lookups
+-- instance not just by type 'R4', but it also already has (pointer to) value
+-- of type 'R4'. And by looking at value it may tell, what type 'a' was used
+-- during its creation. Thus, (because i don't have pointers here) i need a
+-- witness of type 'a' to construct value of type 'R4'.
+data Proxy a = Proxy
+
+-- Go: 'json.Unmarshaler' interface. 'Proxy' serves the role of pointer
+-- receiver for determining into which interface to unmarshal struct fields,
+-- if any.
+class Unmarshaler b a where
+ read' :: Proxy a -> String -> b
+
+-- Read string produced by 'Show' instance: "R4 (S2 1) 2"
+instance (I2 a, Show a) => Unmarshaler R4 a where
+ read' _ (stripPrefix "R4" -> Just i2str) =
+ let [(i2, rest)] = readParen True (reads @a) $ i2str
+ in R4 i2 (read rest)
+
+-- And here it is (note explicit type applications):
+--
+-- ghci> read' @R4 (Proxy @S2) $ show (R4 (S2 1) 2)
+-- R4 (S2 1) 2
+
+main :: IO ()
+main = do
+ let r2 :: R2 S
+ r2 = read $ show (R2 (S 1) 2)
+ print r2
+
+ let r4 :: R4
+ r4 = read' (Proxy @S2) $ show (R4 (S2 1) 2)
+ print r4
+