Как создать и использовать мою собственную структуру / подпись в SML / NJ? - PullRequest
0 голосов
/ 26 ноября 2018

Я новичок в функциональном программировании и хочу создать свою собственную структуру / подпись под названием Словарь.Пока у меня есть это в файле Dictionary-en.sml:

(* The signature DICTIONARY defines a type and a programming interface for
   the dictionary data structure. The data structure allows us to store
   data in the form of (key, value) pairs and to query the data using a key. *)
signature DICTIONARY =
sig

    (* The structure has to implement a dictionary type. It defines key type,
       which has to support equality checking, and a value type for the data
       stored in the dictionary. *)
    type (''key, 'value) dict

    (* Creates an empty dictionary. *)
    val empty: (''key, 'value) dict

    (* Returns true if a key exists in the dictionary. *)
    val exists: (''key, 'value) dict -> ''key -> bool

end

И у меня есть это в файле solution.sml:

structure Dictionary :> DICTIONARY =
struct
    type (''key, 'value) dict = (''key * 'value) list

    val empty = []

    fun exists dict key =
        case dict of
            [] => false
          | (k, _ )::rep => if k = key
                            then true
                            else exists rep key
end

Но я не знаю, как использоватьэтот.Когда я писал в REPL:

- Dictionary.exists [(3,"c"), (5, "e"), (7, "g")] 3;

Я получил эту ошибку:

stdIn:1.2-3.7 Error: operator and operand do not agree [tycon mismatch]
  operator domain: (''Z,'Y) Dictionary.dict
  operand:         ([int ty] * string) list
  in expression:
    Dictionary.exists ((3,"c") :: (5,"e") :: (<exp>,<exp>) :: nil)

Может кто-нибудь помочь мне?Я не знаю, что я сделал не так.

Ответы [ 2 ]

0 голосов
/ 27 ноября 2018

В функции

fun exists dict key =
    case dict of
        [] => []
      | (k, _ )::rep => if k = key
                        then true
                        else exists rep key

Я обнаружил две проблемы:

  • Невозможно вернуть [] в одном месте и trueв другом.
  • Вместо if P then true else Q напишите P orelse Q.

Вы используете :>, что означает, что модуль непрозрачен ,так что вы можете получить доступ только к тем вещам, которые указаны в подписи.Внутреннее представление списка не упоминается в подписи, поэтому вы не можете ссылаться на dict как список, даже если вы знаете, что это так.Это особенность.

Я бы, вероятно, назвал exists для member, поскольку List.exists является предикатом высшего порядка, например, List.exists (fn x => x > 5) [3, 6, 9].Вы также можете отклониться от любого стандартного наименования библиотеки и сказать containsKey и containsValue, или что-то в этом роде.

Помимо функции insert, которую предложил molbdnilo, вы можете захотеть иметь функцию fromList.

Вот измененная версия (комментарии для краткости опущены, но я думаю, что ваши комментарии хороши!):

signature DICTIONARY =
sig
    type (''key, 'value) dict

    val empty: (''key, 'value) dict
    val member: ''key -> (''key, 'value) dict -> bool
    val insert: (''key * 'value) -> (''key, 'value) dict -> (''key, 'value) dict
    val fromList: (''key * 'value) list -> (''key, 'value) dict
end

structure Dictionary :> DICTIONARY =
struct
    type (''key, 'value) dict = (''key * 'value) list

    val empty = []

    fun member key [] = false
      | member key ((key2, _)::dict) =
          key = key2 orelse member key dict

    fun insert (key, value) [] = [(key, value)]
      | insert (key, value) ((key2, value2)::dict) =
          if key = key2
          then (key, value) :: dict
          else (key2, value2) :: insert (key, value) dict

    fun fromList pairs = foldl (fn (pair, dict) => insert pair dict) empty pairs
end

Но поскольку вы создаете модуль словаря,две вещи, которые вы хотите рассмотреть:

  1. Позволяют использовать какое-то двоичное дерево в качестве внутреннего представления, требуя, чтобы ключи были упорядочены , а не по сравнениюна равенство .
  2. Поскольку Standard ML не имеет специального синтаксиса, такого как ''key, для выражения того, что что-то можно заказать (Хаскелл обобщает это как классы типов , но Standard ML имееттолько специальный синтаксис ''key), это хороший случай для использования функторов , которое является именем модулей более высокого порядка, также называемых параметризованными модулями.

HeВот пример подписи, функтора и структуры, которые вы можете заполнить:

signature ORD = sig
  type t
  val compare : t * t -> order
end

signature DICT = sig
  type key
  type 'value dict

  val empty: 'value dict
  val member: key -> 'value dict -> bool
  val insert: key * 'value -> 'value dict -> 'value dict
  val fromList: (key * 'value) list -> 'value dict
end

functor Dict (Ord : ORD) :> DICT = struct
  type key = Ord.t
  type 'value dict = (key * 'value) list

  val empty = ...
  fun member _ _ = raise Fail "not implemented"
  fun insert _ _ = raise Fail "not implemented"
  fun fromList _ = raise Fail "not implemented"
end

На этом этапе вы можете изменить type 'value dict на использование двоичного дерева, и когда вам нужно решить, идти ли налево или направов этом двоичном дереве вы можете написать:

case Ord.compare (key1, key2) of
     LESS => ...
   | EQUAL => ...
   | GREATER => ...

И когда вам нужен словарь, в котором ключ имеет определенный тип или тип , вы можете создать модуль с помощью этого функтора:

structure IntDict = Dict(struct
                           type t = int
                           val compare = Int.compare
                         end)

structure StringDict = Dict(struct
                              type t = string
                              val compare = String.compare
                            end)

См. Также Примеры стандартных функторов ML для дополнительных примеров.

0 голосов
/ 27 ноября 2018

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

Например,

val insert : (''key * 'value) -> (''key, 'value) dict -> (''key, 'value) dict

позволит вам написать

Dictionary.exists (Dictionary.insert (3,"c") Dictionary.empty) 3;

Реализация оставлена ​​как упражнение.

...