Могу ли я аннотировать полный тип объявления `fun`? - PullRequest
0 голосов
/ 18 октября 2018

В каких условиях я могу предоставить сигнатуры типов для функций?

Стандартный ML не имеет сигнатур типа верхнего уровня, таких как Haskell.Вот альтернативы, которые я рассмотрел:

  1. Сигнатуры модуля, для которых требуется либо отдельный файл сигнатуры, либо сигнатура типа, определяемая в отдельном блоке внутри того же файла, что и сам модуль.Это требует использования модулей, и в любой производственной системе это было бы вменяемым выбором.

    Модули могут показаться немного многословными в стаб-файле, когда альтернативой является определение одной функции.Они оба вводят понятие модулей, возможно, немного раньше,

  2. Используя val и val rec Я могу иметь полную сигнатуру типа в одной строке:

    val incr : int -> int =
      fn i => i + 1
    
    val rec map : ('a -> 'b) -> 'a list -> 'b list =
      fn f => fn xs => case xs of
           []    => []
         | x::ys => f x :: map f ys
    

    Могу ли я иметь это, а также использовать fun?

    Если это возможно, я не могу понять синтаксис правильно.

  3. В настоящее время решение заключается во встраивании типов аргументов и типа результата как таковых:

    fun map (f : 'a -> 'b) (xs : 'a list) : 'b list =
      raise Fail "'map' is not implemented"
    

    Но я испытал, что этот синтаксис дает начинающему программисту ML впечатление, что решение либо не может, либо должноне обновляться до модельного решения:

    fun map f [] = []
      | map f (x::xs) = f x :: map f xs
    

    Похоже, что сигнатуры типов, которые должны помочь учащемуся, не позволяют им сопоставляться с образцом.Я не могу сказать, происходит ли это потому, что они думают, что сигнатуры типов не могут быть удалены или их не следует удалять.Конечно, это вопрос стиля, должны ли они (и где), но студент должен иметь возможность исследовать стиль вывода типа.

1 Ответ

0 голосов
/ 18 октября 2018

С помощью функции let или локальной привязки и теневого копирования вы можете объявить функцию, а затем присвоить ей значение.

для этого удобнее использовать local, поскольку она имеет вид: local decl in decl end, а не let decl in expr end, что означает, что expr , хочет получитьаргумент уровня f

val map = fn f => let fun map = ... in map end

Я не верю, что люди обычно используют local , в основном потому, что модули могут делать все, что может локально, и даже больше, но, возможно,стоит рассматривать его как анонимный модуль, когда вы еще не хотите объяснять модули.

local
  fun map (f : 'a -> 'b) (x::rest : 'a list) : 'b list
        = f x :: map f rest
    | map _ ([]) = []

 in
 val (map : ('a -> 'b) -> 'a list -> 'b list) = map;
end

Затем, когда придет время объяснять модули, вы можете объявить структуру внутри локальной, вокруг всехобъявления, а затем удалить локальные, и попытаться придумать ситуацию, когда они закодировали 2 функции, и более уместно заменить 2 локальных, с 1 структурой.

local
  structure X = struct
    fun id x = x
  end
  in val id = X.id 
end

возможно, запуск ихс чем-тог как следующее:

exception ReplaceSorryWithYourAnswer

fun sorry () = raise ReplaceSorryWithYourAnswer

local
  (* Please fill in the _'s with the arguments
     and the call to sorry() with your answer *)
  fun map _ _ = sorry ()
in
  val map : ('a -> 'b) -> ('a list) -> ('b list) = map
end
...