In your example, x is an immutable value that is assigned during runtime (but NOT evaluated lazily), whereas y is assigned during compiletime. As an example,
let myDLL = "foo.dll"
[<DllImport(myDLL, CallingConvention = CallingConvention.Cdecl)>]
extern void HelloWorld()
will not work, because DllImport is an attribute and needs to know the value of myDLL during compilation. However, this will work:
[<Literal>]
let myDLL = "foo.dll"
[<DllImport(myDLL, CallingConvention = CallingConvention.Cdecl)>]
extern void HelloWorld()