2016-04-08 4 views
5

После минимального примера наблюдения (такого рода изумленного меня):частичная деконструкция в сопоставлении с образцом (F #)

type Vector = V of float*float 

// complete unfolding of type is OK 
let projX (V (a,_)) = a 

// also works 
let projX' x = 
    match x with 
    | V (a, _) -> a 

// BUT: 
// partial unfolding is not Ok 
let projX'' (V x) = fst x 

// consequently also doesn't work 
let projX''' x = 
    match x with 
    | V y -> fst y 

Что является причиной того, что делает невозможным для сопоставления частично деконструированного типа?

Некоторых частичных деконструкциев кажется нормально:

// Works 
let f (x,y) = fst y 

EDIT: Хорошо, теперь я понимаю, «техническую» причина поведения, описанное (Спасибо за ваши ответы & комментариев). Тем не менее, я считаю, что язык мудрый, это поведение кажется немного «неестественным» по сравнению с остальной частью языка:

«Алгебраически», мне кажется странным различать тип «t» от типа »(t)». Скобки (в этом контексте) используются для обеспечения приоритета, например, в "(t * s) * r" vs "t * (s * r)". Также FSI ответы соответственно, отправлять ли я

type Vector = (int * int) 

или

type Vector = int * int 

к FSI, ответ всегда

типа Vector = Int * INT

Учитывая те наблюдения, заключают, что «int * int» и «(int * int)» означают точно такие же типы и t что все вхождения одного в любой фрагмент кода могут быть заменены другим (см. прозрачность) ... что, как мы видели, неверно.

Далее представляется важным, что для объяснения поведения мы должны были прибегать к разговорам о том, «как выглядит какой-то код после компиляции», а не о семантических свойствах языка, который указывает, что есть некоторые « напряженности "между семантикой языка и тем, что делает компилятор.

+1

Попробуйте с помощью 'type Vector = V of (float * float)' вместо этого, чтобы компилятор использовал фактический кортеж для содержимого. – kvb

+0

он работает! ... но как это могло измениться ... Я имею в виду тип Vector = (V of float) * float даже недействителен? –

+1

Вопрос в следующем: означает ли 'V of x * y' означает, что V содержит кортеж элементов типов x и y" или "V содержит два разных поля типа x и y"? Если вы не вставляете в конец кортеж, тогда компилятор принимает последнее, но если вы его скопируете в скобки, это означает первое. Это различие в основном имеет значение для взаимодействия с другими языками .NET, но, как вы обнаружили, это может также повлиять на то, как вы взаимодействуете со значениями такого типа внутри F # в некоторых случаях. – kvb

ответ

1

В F #

type Vector = V of float*float 

просто выродились союз (вы можете увидеть, что при наведении его в Visual Studio), так что это эквивалентно:

type Vector = 
    | V of float*float 

Часть после of создает два anonymous field s (как описано в ссылке F #), а конструктор принимает два параметра типа float.

Если определить

type Vector2 = 
    | V2 of (float*float) 

есть только один анонимное поле, которое является кортежем поплавков и конструктор с одним параметром. Как было указано в комментарии, вы можете использовать Vector2 для выполнения нужного соответствия шаблонов.

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

let argsTuple = (1., 1.) 
let v1 = V argsTuple 

Однако, если принять во внимание, что есть скрытый поиск по шаблону, все должно быть ясно.

EDIT:

F# language spec (p 122) четко сказано, что скобка вещества в определениях профсоюзными:

Скобки являются существенными в определениях профсоюзов. Таким образом, следующие два определения отличаются:

type CType = C of int * int

type CType = C of (int * int)

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

Я думаю, что такое поведение согласуется с тем, что вы можете определить более сложные модели в определении союза, например:

type Move = 
     | M of (int * int) * (int * int) 

Будучи в состоянии использовать союз с несколькими аргументами также делает много смысл, особенно в ситуации взаимодействия, при использовании кортежей громоздкий.

Другая вещь, которую вы использовали:

type Vector = int * int 

является type abbreviation, который просто дает имя определенного типа. Размещение круглых скобок вокруг int * int не имеет значения, потому что эти скобки будут рассматриваться как группировка скобок.

+0

Я (понимаю и согласен со всем, что вы говорите, и я соглашусь с этим ответом). Тем не менее, я до сих пор считаю, что дизайн мудрый роль круглых скобок в определениях профсоюзов больше на прагматической, а не на чистой/изящной стороне;). Могут быть определения объединений, где некоторые из круглых скобок для группировки, а другие - как обсуждалось ранее ... Дальнейшие определения формы «... = X of Y» зависят не только от Y »как типа» ... –

+0

Я согласен, что это не самый интуитивный и чистый выбор дизайна с точки зрения синтаксиса; с другой стороны, это тоже уродливо. –

Смежные вопросы