Type inference does not work when passing map function

Primarily; Thanks for taking the time to read my question. If you need more information or want to change something, let me know.

When I pass in an array handler function, type inference doesn't work, but when I add a function to the module instead of entering it, it works.

I tried adding type annotation, but it was simply ignored, and F # warns that the code is less general when called the first time, and then errors with the wrong type a second time.

But if I change:

let handleAction
  //following does not work, comment out next line
  (mapItems : 'a -> 'b [] -> int -> ('b -> 'a -> 'b) -> 'b [])

to

let handleAction
  //following does not work, comment out next line
  (notPassed : 'a -> 'b [] -> int -> ('b -> 'a -> 'b) -> 'b [])

Then it works fine. Trying to remove dependencies up, but cannot get F # to understand the type.

let mapItems
  action
  state 
  index
  handlerfn =
    state
      |> Array.indexed
      |> Array.map (
        fun (i, item) ->
          if index < 0 then
            handlerfn item action
          else if i = index then
            handlerfn item action
          else
            item)

//Mediator calling the handler for the action
let handleAction
  //following does not work, comment out next line
  (mapItems : 'a -> 'b [] -> int -> ('b -> 'a -> 'b) -> 'b [])
  //notPassedIn //uncomment this and it works 
                //even though mapItems here and mapItems
                //passed in are the exact same code
  state
  action =
    match action with
    |Pausable action -> //actions specific to pausable stopwatch
        let handler = 
          mapItems
            action //warning: less generic
            state
            action.index
        match action.``type`` with
          //... pausable actions (added to support pause/continue)
    | StopWatch action -> //actions from stop watch
        let handler = 
          mapItems
            action//error: wrong type
            state
            action.index
        match action.``type`` with
          //...handling stopwatch actions

The full code is here: https://github.com/amsterdamharu/programmingbook/tree/example8

(*
  stopwatch module
*)
//types
type SWActionType =
  | Start          of int
type StopWatchAction = {
  ``type``:SWActionType
  //there may be more than one stopwatch in the application
  index:int
}
type StartDate =
  | NoStartDate
  | Date of int
type SingleStopWatchState = {
  status:string
}
type StopWatchState = SingleStopWatchState []
//handlers for the stopwatch actions
let handleStart current state =
  {state with status = "started"}
//mediator for stopwatch
let StopWatchHandleAction 
  mapItems
  (state:StopWatchState)
  (action:StopWatchAction) =
    let handler = 
      mapItems
        action
        state
        action.index
    match action.``type`` with
      | Start current ->
          handler//call handler with state
            (fun
              (state:SingleStopWatchState)
              (action:StopWatchAction) ->
                (handleStart current state))
(*
  Pausable stopwatch that extends stopwatch and supports
  pause action
*)
type PActionType =
  | Pause          of int
type PausableStopWatchAction = {
  ``type``:PActionType
  index:int
}
type PAction =
  | StopWatch of StopWatchAction
  | Pausable of PausableStopWatchAction
type SinglePausableStopWatchState = {
  status:string
  isPaused:bool
}
type PausableStopWatchState = SinglePausableStopWatchState []
//handlers for pausable stopwatch
let handlePause current (state:SinglePausableStopWatchState) =
  {state with 
    status = "paused"
    isPaused = true
  }
//mediator for pausable stopwatch
let PausableHandleAction
  (mapItems : 'a -> 'b [] -> int -> ('b -> 'a -> 'b) -> 'b [])
  state
  action =
    match action with
    |Pausable action -> //actions specific to pausable stopwatch
        let handler = 
          mapItems
            //warning:This construct causes code to be less generic than indicated by the type annotations. The type variable 'a has been constrained to be type 'PausableStopWatchAction'.
            action
            state
            action.index
        match action.``type`` with
          | Pause current ->
              handler//call handler with state
                (fun
                  state
                  action ->
                    (handlePause current state))
    | StopWatch action -> //actions from stop watch
        let handler = 
          mapItems
            (*
              ERROR
              This expression was expected to have type
              'PausableStopWatchAction'    
              but here has type
              'StopWatchAction'
            *)
            action
            state
            action.index
        match action.``type`` with
          | Start current ->
              handler//call handler with state
                (fun
                  state
                  action -> //would use some of stopwatch handlers here
                    {state with
                      status ="started"
                    })
(*
  Application consuming stopwatch and pausable
*)
type ApplicationState = {
  stopwatch:StopWatchState
  pausablestopwatch:PausableStopWatchState
}
type Action =
  | StopWatch of StopWatchAction
  | PausableStopWatch of PAction
let ArrayHandler
  action
  state 
  index
  handlerfn =
    state
      |> Array.indexed
      |> Array.map (
        fun (i, item) ->
          if index < 0 then
            handlerfn item action
          else if i = index then
            handlerfn item action
          else
            item)
//application mediator:
let handleAction 
  (state : ApplicationState)
  action =
  match action with
    | StopWatch
        action ->
          {state with//return application state
            //set the stopwatch state with updated state
            //  provided by the mediator in stop watch
            stopwatch = 
              StopWatchHandleAction
                ArrayHandler state.stopwatch action}
    | PausableStopWatch 
        action ->
          {state with//return application state
            pausablestopwatch = 
              PausableHandleAction
                ArrayHandler state.pausablestopwatch action}
+1
1

. , .

:

let mkList x = [x]
let mkTwo (f: 'a -> 'a list) = (f 42), (f "abc")
let two = mkTwo mkList

, . , , f: 'a -> 'a list, 'a mkTwo, f. , :

let mkTwo<'a> (f: 'a -> 'a list) = (f 42), (f "abc")

, mkTwo 'a. 'a mkTwo.

: , f 42, : ", f int , 'a int" - : ", , , int. , ".

f "abc". , 'a = int , , f : int -> int list, , string .

mapItems, : PausableStopWatchAction ( ), StopWatchAction ( ).

:

1:

let mkList x = [x]
let mkTwo f g = (f 42), (g "abc")
let two = mkTwo mkList mkList

mkList . , : int -> int list, string -> string list. , mkTwo .

2:

, , , . mapItems :

type MkList =
    abstract member mkList : 'a -> 'a list

let mkList = { new MkList with member this.mkList x = [x] }
let mkTwo (f: MkList) = (f.mkList 42), (f.mkList "abc")
let two = mkTwo mkList

, , , , .

, "" action handlerfn ( , action handlerfn, , , ):

let mapItems
  state 
  index
  handlerfn =
    state
      |> Array.indexed
      |> Array.map (
        fun (i, item) ->
          if index < 0 then
            handlerfn item 
          else if i = index then
            handlerfn item 
          else
            item)

...

let handleAction
  (mapItems : 'a [] -> int -> ('a -> 'a) -> 'a [])
  state
  action =
    match action with
    |Pausable action -> //actions specific to pausable stopwatch
        let handler = 
          mapItems
            state
            action.index
        match action.``type`` with
         | Pause current ->
             handler//call handler with state
               (fun state ->
                     (handlePause current state))
    | StopWatch action -> //actions from stop watch
       let handler = 
         mapItems
           state
           action.index
       match action.``type`` with
         | Start current ->
             handler//call handler with state
               (fun state ->
                   //would use some of stopwatch handlers here
                   {state with
                     status ="started"
                   })
+6

Source: https://habr.com/ru/post/1683438/


All Articles