docs: def construct(arg):
      '''
      Shortcut syntax to define trafarets.
  
      - int, str, float and bool will return t.Int, t.String, t.Float and t.Bool
      - one element list will return t.List
      - tuple or list with several args will return t.Tuple
      - dict will return t.Dict. If key has '?' at the and it will be optional and '?' will be removed
      - any callable will be t.Call
      - otherwise it will be returned as is
  
      construct is recursive and will try construct all lists, tuples and dicts args
      '''
      if isinstance(arg, t.Trafaret):
          return arg
      elif isinstance(arg, tuple) or (isinstance(arg, list) and len(arg) > 1):
          return t.Tuple(*(construct(a) for a in arg))
      elif isinstance(arg, list):
          # if len(arg) == 1
          return t.List(construct(arg[0]))
      elif isinstance(arg, dict):
          return t.Dict({construct_key(key): construct(value) for key, value in arg.items()})
      elif isinstance(arg, str):
          return t.Atom(arg)
      elif isinstance(arg, type):
          if arg is int:
              return t.Int()
          elif arg is float:
              return t.Float()
          elif arg is str:
              return t.String()
          elif arg is bool:
              return t.Bool()
          else:
              return t.Type(arg)
      elif callable(arg):
          return t.Call(arg)
      else:
          return arg