func dhallShim(out reflect.Type, dhallFunc core.Callable) func([]reflect.Value) []reflect.Value {
	return func(args []reflect.Value) []reflect.Value {
		var expr core.Value = dhallFunc
		for _, arg := range args {
			fn := expr.(core.Callable)
			dhallArg, err := encode(arg, fn.ArgType())
			if err != nil {
				panic(err)
			}
			expr = fn.Call(dhallArg)
		}
		ptr := reflect.New(out)
		err := decode(expr, ptr.Elem())
		if err != nil {
			panic(err)
		}
		return []reflect.Value{ptr.Elem()}
	}
}
dhallShim takes a Callable and wraps it so that it can be passed
to reflect.MakeFunc().  This means it converts reflect.Value inputs
to core.Value inputs, and converts core.Value outputs to
reflect.Value outputs.
package dhall
import (
	"errors"
	"fmt"
	"io"
	"reflect"
	"github.com/philandstuff/dhall-golang/v6/core"
	"github.com/philandstuff/dhall-golang/v6/imports"
	"github.com/philandstuff/dhall-golang/v6/parser"
	"github.com/philandstuff/dhall-golang/v6/term"
)
func isMapEntryType(recordType map[string]core.Value) bool {
	if _, ok := recordType["mapKey"]; ok {
		if _, ok := recordType["mapValue"]; ok {
			return len(recordType) == 2
		}
	}
	return false
}
var JSONType core.Value = mkJSONType()
var identity core.Value = core.Eval(term.NewLambda("_", term.Type, term.NewVar("_")))
var jsonConstructors core.Value = core.RecordLit{
	"array":   identity,
	"bool":    identity,
	"double":  identity,
	"integer": identity,
	"null":    core.NoneOf{},  
	"object":  identity,
	"string":  identity,
}
func mkJSONType() core.Value {
	return core.Pi{
		Label: "JSON",
		Domain: core.Type,
		Codomain: func(JSON core.Value) core.Value {
			return core.Pi{
				Label: "json",
				Domain: core.RecordType{
					"array": core.Pi{
						Label: "_",
						Domain: core.ListOf{JSON},
						Codomain: func(_ core.Value) core.Value{
							return JSON
						},
					},
					"bool": core.Pi{
						Label: "_",
						Domain: core.Bool,
						Codomain: func(_ core.Value) core.Value{
							return JSON
						},
					},
					"double": core.Pi{
						Label: "_",
						Domain: core.Double,
						Codomain: func(_ core.Value) core.Value{
							return JSON
						},
					},
					"integer": core.Pi{
						Label: "_",
						Domain: core.Integer,
						Codomain: func(_ core.Value) core.Value{
							return JSON
						},
					},
					"null": JSON,
					"object": core.Pi{
						Label: "_",
						Domain: core.ListOf{
							Type: core.RecordType{
								"mapKey": core.Text,
								"mapValue": JSON,
							},
						},
						Codomain: func(_ core.Value) core.Value{
							return JSON
						},
					},
					"string": core.Pi{
						Label: "_",
						Domain: core.Text,
						Codomain: func(_ core.Value) core.Value{
							return JSON
						},
					},
				},
				Codomain: func(json core.Value) core.Value {
					return JSON
				},
			}
		},
	}
}
func Unmarshal(b []byte, out interface{}) error {
	term, err := parser.Parse("-", b)
	if err != nil {
		return err
	}
	return unmarshalTerm(term, out)
}
func UnmarshalReader(filename string, r io.Reader, out interface{}) error {
	term, err := parser.ParseReader(filename, r)
	if err != nil {
		return err
	}
	return unmarshalTerm(term, out)
}
func UnmarshalFile(filename string, out interface{}) error {
	term, err := parser.ParseFile(filename)
	if err != nil {
		return err
	}
	return unmarshalTerm(term, out)
}
func unmarshalTerm(term term.Term, out interface{}) error {
	resolved, err := imports.Load(term)
	if err != nil {
		return err
	}
	_, err = core.TypeOf(resolved)
	if err != nil {
		return err
	}
	return Decode(core.Eval(resolved), out)
}
func Decode(e core.Value, out interface{}) error {
	v := reflect.ValueOf(out)
	return decode(e, v.Elem())
}
func encode(val reflect.Value, typ core.Value) (core.Value, error) {
	if opt, ok := typ.(core.OptionalOf); ok {
		switch val.Kind() {
		case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map,
			reflect.Ptr, reflect.Slice:
			if val.IsNil() {
				return core.NoneOf{Type: typ}, nil
			}
		}
		dhallVal, err := encode(val, opt.Type)
		if err != nil {
			return nil, err
		}
		return core.Some{Val: dhallVal}, nil
	}
	switch val.Kind() {
	case reflect.Bool:
		if typ == core.Bool {
			return core.BoolLit(val.Bool()), nil
		}
	case reflect.Int, reflect.Int8, reflect.Int16,
		reflect.Int32, reflect.Int64:
		if typ == core.Integer {
			return core.IntegerLit(val.Int()), nil
		}
	case reflect.Uint, reflect.Uint8, reflect.Uint16,
		reflect.Uint32, reflect.Uint64, reflect.Uintptr:
		if typ == core.Natural {
			return core.NaturalLit(val.Uint()), nil
		}
	case reflect.Float32, reflect.Float64:
		if typ == core.Double {
			return core.DoubleLit(val.Float()), nil
		}
	case reflect.Func:  
	case reflect.Map:
		listOf, ok := typ.(core.ListOf)
		if !ok {
			break
		}
		mapEntryType, ok := listOf.Type.(core.RecordType)
		if !ok {
			break
		}
		if !isMapEntryType(mapEntryType) {
			break
		}
		if val.Len() == 0 {
			return core.EmptyList{Type: mapEntryType}, nil
		}
		l := make(core.NonEmptyList, val.Len())
		iter := val.MapRange()
		i := 0
		for iter.Next() {
			key, err := encode(iter.Key(), mapEntryType["mapKey"])
			if err != nil {
				return nil, err
			}
			val, err := encode(iter.Value(), mapEntryType["mapValue"])
			if err != nil {
				return nil, err
			}
			l[i] = core.RecordLit{
				"mapKey":   key,
				"mapValue": val,
			}
			i++
		}
		return l, nil
	case reflect.Ptr:
		return encode(val.Elem(), typ)
	case reflect.Slice:
		e, ok := typ.(core.ListOf)
		if !ok {
			break
		}
		if val.Len() == 0 {
			return core.EmptyList{Type: e.Type}, nil
		}
		l := make(core.NonEmptyList, val.Len())
		var err error
		for i := 0; i < val.Len() && err == nil; i++ {
			l[i], err = encode(val.Index(i), e.Type)
		}
		return l, err
	case reflect.String:
		if typ == core.Text {
			return core.PlainTextLit(val.String()), nil
		}
	case reflect.Struct:
		e, ok := typ.(core.RecordType)
		if !ok {
			break
		}
		rec := core.RecordLit{}
	fields:
		for key, typ := range e {
			var err error
			structType := val.Type()
			for i := 0; i < structType.NumField(); i++ {
				tag := structType.Field(i).Tag.Get("dhall")
				if key == tag {
					rec[key], err = encode(val.Field(i), typ)
					if err != nil {
						return nil, err
					}
					continue fields
				}
			}
			rec[key], err = encode(val.FieldByName(key), typ)
			if err != nil {
				return nil, err
			}
		}
		return rec, nil
	}
	return nil, fmt.Errorf("Can't encode %v as %v", val, typ)
}