Я просто установил последнюю версию F# и открыл старое решение видеть то, что это скажет мне.
Это - многофайловое решение, где первый файл включает некоторые 'дополнительные функции' в модуль Списка:
module List =
///Given list of 'rows', returns list of 'columns'
let rec transpose lst =
match lst with
| (_::_)::_ -> List.map List.hd lst :: transpose (List.map List.tl lst)
| _ -> []
Компилятор больше не любит это и говорит:
Файлы в библиотеках или приложениях нескольких-файлов должны начаться с пространства имен или объявления модуля, например, 'пространства имен SomeNamespace. SubNamespace' или 'модуль SomeNamespace. SomeModule'
Но если я делаю это:
module Foo.List =
Это говорит:
Сокращение модуля должно быть простым именем, не путем
Что я пропускаю здесь? И каково решение для этого 'специального' случая, где я расширяю модуль, который прибывает откуда-либо?
Во-первых, вы имеете в виду «typedef», а не «typecast» в вашем вопросе.
В C указатель на тип T
может указывать на объект типа T
:
int *pi;
int i;
pi = &i;
. Теперь давайте сделаем это немного сложнее. Вы, кажется, знаете разницу между массивами и указателями (то есть, вы знаете, что массивы не указатели, они ведут себя как они иногда). Так, вы должны уметь понимать:
int a[3];
int *pa = a;
Но для полноты: в присвоении имя a
эквивалентно & a [0]
, т.е. указатель на первый элемент массива a
. Если вы не уверены в том, как и почему это работает, есть много ответов, объясняющих, когда именно имя массива «распадается» на указатель, а когда нет:
Я уверен, что есть еще много таких вопросов и ответов на SO, я только что упомянул некоторые, что я нашел из поиска.
Вернемся к теме
int foo[2][4];
foo
имеет тип «массив [2]
массива [3]
int
». Это означает, что foo [0]
является массивом 3 int
s, а foo [1]
является массивом 3 int
s.
Теперь предположим, что мы хотим объявить указатель, и мы хотим присвоить его foo [0]
. То есть мы хотим сделать:
/* declare p somehow */
p = foo[0];
Вышеуказанное не отличается по форме от int * pa = a;
, потому что типы a
и foo [0]
одинаковы. Итак, нам нужно int * p;
как наше объявление p
.
Главное, что нужно помнить о массивах, это то, что «правило» о затухании имени массива до указателя на его первый элемент применяется только один раз. Если имеется массив массива, то в контекстах значений имя массива будет распадаться не на тип «указатель на указатель», а на тип «указатель на массив». Возвращаясь к foo
:
/* What should be the type of q? */
q = foo;
Имя foo
выше является указателем на первый элемент foo
, т.е. можно записать выше как:
q = &foo[0];
Тип foo [0]
является «array [3]
of int
». Поэтому нам нужно, чтобы q
был указателем на «массив [3]
из int
»:
int (*q)[3];
Скобки вокруг q
необходимы, потому что []
связывается более плотно, чем *
в C, поэтому int * q [3]
объявляет q
как массив int * (q [3])
- это, сверху, эквивалент int * q [3]
, т.е. массив 3 указателей на int
.
Надеюсь, что это поможет. Вы также должны прочитать C для smarties: массивы и указатели для действительно хорошего учебного пособия по этой теме.
О чтении деклараций вообще: вы читаете их "наизнанку", начиная с имени "переменной" (если она есть). Вы идете налево как можно больше, если нет []
непосредственно справа, и вы всегда соблюдаете круглые скобки. cdecl
должен в какой-то степени помочь:
$ cdecl
cdecl> declare p as pointer to array 3 of int
int (*p)[3]
cdecl> explain int (*p)[3]
declare p as pointer to array 3 of int
Читать
int (*a)[3];
a # "a is"
(* ) # parentheses, so precedence changes.
# "a pointer to"
[3] # "an array [3] of"
int ; # "int".
Для
int *a[3];
a # "a is"
[3] # "an array [3] of"
* # can't go right, so go left.
# "pointer to"
int ; # "int".
Для
char *(*(*a[])())()
a # "a is"
[] # "an array of"
* # "pointer to"
( )() # "function taking unspecified number of parameters"
(* ) # "and returning a pointer to"
() # "function"
char * # "returning pointer to char"
(Пример из c-faq вопрос 1,21 . На практике, если вы читаете такое сложное заявление, с кодом что-то серьезно не так!)
-121--1586566-явно преобразовать его в int first
(<= 0x20 (int current) 0xD7FF)
-121--3941991- Сделать пространство имен явным:
namespace Microsoft.FSharp.Collections
module List =
///Given list of 'rows', returns list of 'columns'
let rec transpose lst =
match lst with
| (_::_)::_ -> List.map List.head lst :: transpose (List.map List.tail lst)
| _ -> []
Обратите внимание, что List.hd
и List.tl
были переименованы в List.head
и List.tail