anchor.diff:              then acc
               else acc @ Error.AsResult(sprintf "Fragment '%s' is not used in any operation in the document. Fragments must be used in at least one operation." def.Name.Value)) Success
   
  -    let rec private fragmentSpreadTargetDefinedInSelection (acc : ValidationResult) (fragmentDefinitionNames : string list) (path : Path) =
  +    let rec private fragmentSpreadTargetDefinedInSelection (fragmentDefinitionNames : string list) (path : Path) =
           function
  -        | Field field -> 
  +        | Field field ->
               let path = field.AliasOrName :: path
  -            match field.SelectionSet |> List.map (fragmentSpreadTargetDefinedInSelection acc fragmentDefinitionNames path) with
  -            | [] -> acc
  -            | results -> List.reduce (@) results
  +            field.SelectionSet
  +            |> collectResults(fragmentSpreadTargetDefinedInSelection fragmentDefinitionNames path)
           | InlineFragment frag ->
  -            match frag.SelectionSet |> List.map (fragmentSpreadTargetDefinedInSelection acc fragmentDefinitionNames path) with
  -            | [] -> acc
  -            | results -> List.reduce (@) results
  +            frag.SelectionSet
  +            |> collectResults (fragmentSpreadTargetDefinedInSelection fragmentDefinitionNames path)
           | FragmentSpread spread ->
               if List.contains spread.Name fragmentDefinitionNames
  -            then acc
  -            else acc @ Error.AsResult(sprintf "Fragment spread '%s' refers to a non-existent fragment definition in the document." spread.Name, path)
  +            then Success
  +            else Error.AsResult(sprintf "Fragment spread '%s' refers to a non-existent fragment definition in the document." spread.Name, path)
   
       let internal validateFragmentSpreadTargetDefined (ctx : ValidationContext) =
           let fragmentDefinitionNames = ctx.FragmentDefinitions |> List.choose (fun def -> def.Name)
           ctx.Document.Definitions
  -        |> List.fold (fun acc def ->
  -            match def with
  -            | FragmentDefinition frag -> 
  -                let path = match frag.Name with | Some name -> [name] | None -> []
  -                match frag.SelectionSet |> List.map (fragmentSpreadTargetDefinedInSelection acc fragmentDefinitionNames path) with
  -                | [] -> acc
  -                | results -> List.reduce (@) results
  -            | OperationDefinition odef ->
  -                let path = match odef.Name with | Some name -> [name] | None -> []
  -                match odef.SelectionSet |> List.map (fragmentSpreadTargetDefinedInSelection acc fragmentDefinitionNames path) with
  -                | [] -> acc
  -                | results -> List.reduce (@) results) Success
  -
  -    let rec private checkFragmentMustNotHaveCycles (acc : ValidationResult) (fragmentDefinitions : FragmentDefinition list) (visited : string list ref) (validated : string list ref) (frag : FragmentDefinition) =
  -        frag.Name 
  +        |> collectResults(function
  +                          | FragmentDefinition frag ->
  +                              let path = Option.toList frag.Name
  +                              frag.SelectionSet
  +                              |> collectResults (fragmentSpreadTargetDefinedInSelection fragmentDefinitionNames path)
  +                          | OperationDefinition odef ->
  +                              let path = Option.toList odef.Name
  +                              odef.SelectionSet
  +                              |> collectResults (fragmentSpreadTargetDefinedInSelection fragmentDefinitionNames path))
  +
  +    let rec private checkFragmentMustNotHaveCycles (fragmentDefinitions : FragmentDefinition list) (visited : string list ref) (validated : string list ref) (frag : FragmentDefinition) =
  +        frag.Name
           |> Option.map (fun name ->
               if List.contains name !visited
               then
                   if not (List.contains name !validated) then
                       validated := name :: !validated
  -                    acc @ Error.AsResult(sprintf "Fragment '%s' is making a cyclic reference." name)
  -                else acc
  +                    Error.AsResult(sprintf "Fragment '%s' is making a cyclic reference." name)
  +                else Success
               else
  +                // FIXME: Use a Dictionary instead
                   visited := name :: !visited
  -                match frag.SelectionSet |> List.map (checkFragmentsMustNotHaveCyclesInSelection acc fragmentDefinitions visited validated) with
  -                | [] -> acc
  -                | results -> List.reduce (@) results)
  -        |> Option.defaultValue acc
  -
  -    and private checkFragmentsMustNotHaveCyclesInSelection (acc : ValidationResult) (fragmentDefinitions : FragmentDefinition list) (visited : string list ref) (validated : string list ref) =
  +                frag.SelectionSet
  +                |> collectResults (checkFragmentsMustNotHaveCyclesInSelection fragmentDefinitions visited validated))
  +        |> Option.defaultValue Success
  +
  +    and private checkFragmentsMustNotHaveCyclesInSelection (fragmentDefinitions : FragmentDefinition list) (visited : string list ref) (validated : string list ref) =
           function
  -        | Field field -> 
  -            match field.SelectionSet |> List.map (checkFragmentsMustNotHaveCyclesInSelection acc fragmentDefinitions visited validated) with
  -            | [] -> acc
  -            | results -> List.reduce (@) results
  -        | InlineFragment frag -> checkFragmentMustNotHaveCycles acc fragmentDefinitions visited validated frag
  +        | Field field ->
  +            field.SelectionSet
  +            |> collectResults (checkFragmentsMustNotHaveCyclesInSelection fragmentDefinitions visited validated)
  +        | InlineFragment frag -> checkFragmentMustNotHaveCycles fragmentDefinitions visited validated frag
           | FragmentSpread spread ->
               match fragmentDefinitions |> List.tryFind (fun f -> f.Name.IsSome && f.Name.Value = spread.Name) with
  -            | Some frag -> checkFragmentMustNotHaveCycles acc fragmentDefinitions visited validated frag
  -            | None -> acc
  +            | Some frag -> checkFragmentMustNotHaveCycles fragmentDefinitions visited validated frag
  +            | None -> Success
   
       let internal validateFragmentsMustNotFormCycles (ctx : ValidationContext) =
           let fragmentDefinitions = ctx.FragmentDefinitions |> List.map (fun x -> x.Definition)
           let visited, validated = ref [], ref []
  -        fragmentDefinitions |> List.fold (fun acc def -> checkFragmentMustNotHaveCycles acc fragmentDefinitions visited validated def) Success
  -
  -    let private checkFragmentSpreadIsPossibleInSelection (acc : ValidationResult) (path : Path, parentType : IntrospectionType, fragmentType : IntrospectionType) =
  +        fragmentDefinitions
  +        |> collectResults (checkFragmentMustNotHaveCycles fragmentDefinitions visited validated)
  +
  +    let private checkFragmentSpreadIsPossibleInSelection (path : Path, parentType : IntrospectionType, fragmentType : IntrospectionType) =
           if not (typesAreApplicable (parentType, fragmentType))
  -        then acc @ Error.AsResult(sprintf "Fragment type condition '%s' is not applicable to the parent type of the field '%s'." fragmentType.Name parentType.Name, path)
  -        else acc
  -
  +        then Error.AsResult(sprintf "Fragment type condition '%s' is not applicable to the parent type of the field '%s'." fragmentType.Name parentType.Name, path)
  +        else Success
  +
  +    // FIXME: Use a fold
       let rec private getFragmentAndParentTypes (acc : (Path * IntrospectionType * IntrospectionType) list) (set : SelectionInfo list) =
           match set with
           | [] -> acc
  
positive.code:                 | _ -> canNotCoerce
              | ListValue values ->
                  match tref.Kind with
                  | TypeKind.LIST when tref.OfType.IsSome && values.Length > 0 -> values |> List.map (checkIsCoercible tref.OfType.Value argName) |> List.reduce (@)
                  | TypeKind.LIST when tref.OfType.IsSome -> acc
                  | _ -> canNotCoerce
              | ObjectValue props ->
                  match tref.Kind with
                  | TypeKind.OBJECT | TypeKind.INTERFACE | TypeKind.UNION | TypeKind.INPUT_OBJECT when tref.Name.IsSome ->
                      match schemaInfo.TryGetTypeByRef(tref) with
                      | Some itype ->
                          let fieldMap = itype.InputFields |> Option.defaultValue [||] |> Array.map (fun x -> x.Name, x.Type) |> List.ofArray |> getFieldMap Map.empty
                          let acc =
                              fieldMap |> Seq.fold (fun acc kvp -> 
                                  if kvp.Value.Kind = TypeKind.NON_NULL && not (props.ContainsKey(kvp.Key))
                                  then acc @ Error.AsResult (sprintf "Can not coerce argument '%s'. Argument definition '%s' have a required field '%s', but that field does not exist in the literal value for the argument." argName tref.Name.Value kvp.Key, selection.Path)
                                  else acc) acc
                          props |> Seq.fold (fun acc kvp ->
                              match fieldMap.TryFind(kvp.Key) with
                              | Some fieldTypeRef -> checkIsCoercible fieldTypeRef kvp.Key kvp.Value
                              | None -> acc @ Error.AsResult(sprintf "Can not coerce argument '%s'. The field '%s' is not a valid field in the argument definition." argName kvp.Key, selection.Path)) acc
                      | None -> canNotCoerce
                  | _ -> canNotCoerce
              | Variable varName ->
                  let variableDefinition = 
                      variables
                      |> Option.defaultValue [] 
                      |> List.tryFind (fun v -> v.VariableName = varName)
                      |> Option.map (fun v -> v, schemaInfo.TryGetInputType(v.Type))
                  match variableDefinition with
                  | Some (vdef, Some vtype) when vdef.DefaultValue.IsSome -> checkIsCoercible vtype argName vdef.DefaultValue.Value
                  | Some (vdef, None) when vdef.DefaultValue.IsSome -> canNotCoerce
                  | _ -> acc
          selection.Field.Arguments
          |> List.fold (fun acc arg ->
              let argumentTypeRef = selection.InputValues |> Option.defaultValue [||] |> Array.tryFind (fun x -> x.Name = arg.Name) |> Option.map (fun x -> x.Type)
              match argumentTypeRef with
              | Some argumentTypeRef -> acc @ (checkIsCoercible argumentTypeRef arg.Name arg.Value)
              | None -> acc) acc
  
      let internal validateInputValues (ctx : ValidationContext) =
          ctx.Definitions
          |> List.choose (function
              | OperationDefinitionInfo odef -> Some (Some odef.Definition.VariableDefinitions, odef.SelectionSet)
              | FragmentDefinitionInfo fdef -> Some (None, fdef.SelectionSet))
          |> List.fold (fun acc (vars, selectionSet) -> selectionSet |> List.fold (fun acc selection -> checkInputValue acc ctx.Schema vars selection) acc) Success
  
      let rec private getDistinctDirectiveNamesInSelection (path : Path) (selection : Selection) : (Path * Set<string>) list =
          match selection with
  
negative.code:                 then acc
                  else acc @ Error.AsResult(sprintf "Directive '%s' is not defined in the schema." name, path)) acc) Success
  
      let private validateDirective (schemaInfo : SchemaInfo) (path : Path) (location : DirectiveLocation) (onError : Directive -> string) (directive : Directive) : ValidationResult =
          schemaInfo.Directives
          |> collectResults(fun d ->
              if d.Name = directive.Name
              then
                  if d.Locations |> Array.contains location then Success
                  else Error.AsResult (onError directive, path)
              else Success)
  
      let rec private checkDirectivesInSelectionSet (schemaInfo : SchemaInfo) (fragmentDefinitions : FragmentDefinition list) (path : Path) (visitedFragments : string list ref) (selectionSet : Selection list) =
          selectionSet
          |> collectResults (checkDirectivesInValidLocationOnSelection schemaInfo fragmentDefinitions path visitedFragments)
  
      and private checkDirectivesInFragment (schemaInfo : SchemaInfo)  (fragmentDefinitions : FragmentDefinition list) (path : Path) (visitedFragments : string list ref) (frag : FragmentDefinition) =
          let expectedLocation =
              match frag.Name with
              | Some _ -> DirectiveLocation.FRAGMENT_DEFINITION
              | None -> DirectiveLocation.INLINE_FRAGMENT
          let directivesValid =
              frag.Directives
              |> collectResults (validateDirective schemaInfo path expectedLocation (fun d ->
                  match frag.Name with
                  | Some fragName -> sprintf "Fragment definition '%s' has a directive '%s', but this directive location is not supported by the schema definition." fragName d.Name
                  | None -> sprintf "An inline fragment has a directive '%s', but this directive location is not supported by the schema definition." d.Name))
  
          // FIXME: Could be buggy
          match frag.Name with
          | Some fragName when List.contains fragName !visitedFragments -> directivesValid
          | _ -> checkDirectivesInSelectionSet schemaInfo fragmentDefinitions path visitedFragments frag.SelectionSet
  
      and private checkDirectivesInValidLocationOnSelection (schemaInfo : SchemaInfo) (fragmentDefinitions : FragmentDefinition list) (path : Path) (visitedFragments : string list ref) =
          function
          | Field field ->
              let path = field.AliasOrName :: path
              let directivesValid =
                  field.Directives
                  |> collectResults(validateDirective schemaInfo path DirectiveLocation.FIELD (fun directiveDef ->
                      sprintf "Field or alias '%s' has a directive '%s', but this directive location is not supported by the schema definition." field.AliasOrName directiveDef.Name))
              directivesValid @ (checkDirectivesInSelectionSet schemaInfo fragmentDefinitions path visitedFragments field.SelectionSet)
          | InlineFragment frag -> checkDirectivesInFragment schemaInfo fragmentDefinitions path visitedFragments frag
          | FragmentSpread spread ->
              spread.Directives
              |> collectResults(validateDirective schemaInfo path DirectiveLocation.FRAGMENT_SPREAD (fun directiveDef ->
                  sprintf "Fragment spread '%s' has a directive '%s', but this directive location is not supported by the schema definition." spread.Name directiveDef.Name))
  
      let private checkDirectivesInOperation (schemaInfo : SchemaInfo) (fragmentDefinitions : FragmentDefinition list) (path : Path) (visitedFragments : string list ref) (operation : OperationDefinition) =
          let expectedLocation =
              match operation.OperationType with
              | Query -> DirectiveLocation.QUERY
              | Mutation -> DirectiveLocation.MUTATION
              | Subscription -> DirectiveLocation.SUBSCRIPTION
          let acc =
              operation.Directives
              |> collectResults(validateDirective schemaInfo path expectedLocation (fun directiveDef ->
                  match operation.Name with
                  | Some operationName -> sprintf "%s operation '%s' has a directive '%s', but this directive location is not supported by the schema definition." (operation.OperationType.ToString()) operationName directiveDef.Name
                  | None -> sprintf "This %s operation has a directive '%s', but this directive location is not supported by the schema definition." (operation.OperationType.ToString()) directiveDef.Name))
          operation.SelectionSet
          |> collectResults(checkDirectivesInValidLocationOnSelection schemaInfo fragmentDefinitions path visitedFragments)
  
      let internal validateDirectivesAreInValidLocations (ctx : ValidationContext) =
          let fragmentDefinitions = ctx.FragmentDefinitions |> List.map (fun x -> x.Definition)
          let visitedFragments = ref []
          ctx.Document.Definitions
          |> collectResults(fun def ->
              let path = def.Name |> Option.toList
              match def with
              | OperationDefinition odef -> checkDirectivesInOperation ctx.Schema fragmentDefinitions path visitedFragments odef
              | FragmentDefinition frag -> checkDirectivesInFragment ctx.Schema fragmentDefinitions path visitedFragments frag)
  
      let rec private getDirectiveNamesInSelection (path : Path) (selection : Selection) : (Path * string list) list =
          match selection with
  