Как можно ограничить использование типа F # Union определенным параметром - PullRequest
0 голосов
/ 12 ноября 2018

Я учу себя F # - для удовольствия и прибыли! - и хотя я сделал несколько шагов, я наткнулся на камень преткновения с использованием алгебраических типов. Ниже приведен тип JSON, который я кодировал для сериализации произвольной структуры JSON в строку. Конечно, я открыт для субъективных комментариев относительно его дизайна и эффективности, но в основном я сосредоточен на строке 7:

type JSON =
    | JString of string
    | JNumber of decimal
    | JBool   of bool
    | JNull
    | JArray  of JSON list
    | JObject of Map< JSON, JSON >
with
    member this.Serialize  =
        let rec serialize ( element : JSON ) =
            match element with
            | JString str ->
                "\"" + str + "\""
            | JNumber num ->
                num.ToString()
            | JBool   bln -> 
                bln.ToString().ToLower()
            | JNull       ->
                "null"
            | JArray  ary ->
                "[" + String.concat "," ( List.map serialize ary ) + "]"
            | JObject obj -> 
                "{" + (
                    Map.fold (
                        fun state key value ->
                            state + ( match state with "" -> "" | _ -> "," )
                                  + ( serialize key ) 
                                  + ":" 
                                  + ( serialize value ) ) "" obj ) + "}"
        serialize( this )

Любой, кто знаком с JSON, знает, что пара ключ / значение объекта JSON должна указываться в строке, а не только в любом элементе / значении JSON. Есть ли способ дополнительно ограничить первый тип параметра карты? Это, конечно, не работает:

type JSON =
    ... elided ...
    | JObject of Map< JSON.JString, JSON >

...

type JSON =
    ... elided ...
    | JObject of Map< JString, JSON >

...

type JSON =
    ... elided ...
    | JObject of Map< string, JSON >

Спасибо.

1 Ответ

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

Ссылка на другой идентификатор дела из дискриминационного союза невозможна. Из Дискриминационных Союзов ,

Синтаксис

[атрибуты]

type [accessibility-modifier] type-name =

| case-identifier1 [of [fieldname1:] type1 [* [fieldname2:] type2 ...]

| case-identifier2 [of [fieldname3:] type3 [* [fieldname4:] type4 ...]

[список участников]

Это означает, что каждый идентификатор дела должен быть of некоторого типа. Сам идентификатор дела не тип.

Один из способов добиться той же функциональности - разбить дискриминируемый союз на несколько дискриминируемых союзов:

type JSONKey =
| JString of string

type JSONValue =
| JString of string
| JNumber of decimal
| JBool of bool
| JNull
| JArray of JSONValue list
| JObject of Map<JSONKey, JSONValue>

и затем определение JSON как:

type JSON = Map<JSONKey, JSONValue>

Тогда serialize нужно будет изменить на let rec serialize ( element : JSONValue ) а также serialize( this ) необходимо изменить на serialize( JObject this ).


Как уже упоминалось @ Ringil , Map<string, JSON> будет работать в этой ситуации, но это не слишком расширяемо / ограничительно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...