Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions FSharp/DatabaseNormalization/DatabaseNormalization.fsproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
</PropertyGroup>

<ItemGroup>
<Compile Include="NormalizationForms.fs" />
</ItemGroup>

</Project>
247 changes: 247 additions & 0 deletions FSharp/DatabaseNormalization/NormalizationForms.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,247 @@
namespace DatabaseNormalization

open System.Collections.Generic

Comment on lines +3 to +4
Copy link

Copilot AI Dec 31, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The System.Collections.Generic namespace is imported but never used in the code. Consider removing this unused import to keep the code clean.

Suggested change
open System.Collections.Generic

Copilot uses AI. Check for mistakes.
// 基础类型定义
Copy link

Copilot AI Dec 31, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment contains Chinese characters. For consistency and accessibility in an English codebase, comments should be written in English. Consider translating to "Basic type definitions".

Copilot uses AI. Check for mistakes.
type AttributeName = string
type RelationName = string

type CellValue =
| Null
| Int of int
| String of string
| Bool of bool
| Float of float
| Date of System.DateTime

interface System.IComparable with
member this.CompareTo(other) =
match other with
| :? CellValue as o ->
match this, o with
| Null, Null -> 0
| Null, _ -> -1
| _, Null -> 1
| Int a, Int b -> compare a b
| String a, String b -> compare a b
| Bool a, Bool b -> compare a b
| Float a, Float b -> compare a b
| Date a, Date b -> compare a b
| _ -> 0
| _ -> -1

type Domain = Set<CellValue>
type AttributeSet = Set<AttributeName>
type Tuple = Map<AttributeName, CellValue>

// 函数依赖 (Functional Dependency)
type FunctionalDependency = {
Left: AttributeSet // X
Right: AttributeSet // Y
// 表示 X -> Y
}
Comment on lines +37 to +42
Copy link

Copilot AI Dec 31, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comments contain Chinese characters. For consistency and accessibility in an English codebase, comments should be written in English. Consider translating to "// Functional Dependency" and "// Represents X -> Y".

Copilot uses AI. Check for mistakes.

// 多值依赖 (Multivalued Dependency)
type MultivaluedDependency = {
Left: AttributeSet // X
Right: AttributeSet // Y
// 表示 X ->-> Y
}
Comment on lines +44 to +49
Copy link

Copilot AI Dec 31, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comments contain Chinese characters. For consistency and accessibility in an English codebase, comments should be written in English. Consider translating to "// Multivalued Dependency" and "// Represents X ->-> Y".

Copilot uses AI. Check for mistakes.

// 连接依赖 (Join Dependency)
Copy link

Copilot AI Dec 31, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment contains Chinese characters. For consistency and accessibility in an English codebase, comments should be written in English. Consider translating to "// Join Dependency".

Suggested change
// 连接依赖 (Join Dependency)
// Join Dependency

Copilot uses AI. Check for mistakes.
type JoinDependency = {
Decomposition: AttributeSet list
}

// 基础关系
Copy link

Copilot AI Dec 31, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment contains Chinese characters. For consistency and accessibility in an English codebase, comments should be written in English. Consider translating to "// Basic relation".

Suggested change
// 基础关系
// Basic relation

Copilot uses AI. Check for mistakes.
type Relation = {
Name: RelationName
Attributes: AttributeName list
Tuples: Tuple list
}

// 1NF: First Normal Form
type Relation1NF = {
Relation: Relation
// 所有属性值必须是原子的(不可再分)
Copy link

Copilot AI Dec 31, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment contains Chinese characters. For consistency and accessibility in an English codebase, comments should be written in English. Consider translating to "// All attribute values must be atomic (indivisible)".

Copilot uses AI. Check for mistakes.
}

module Relation1NF =
let isAtomic (value: CellValue) =
// 在我们的定义中,所有 CellValue 都是原子的
Copy link

Copilot AI Dec 31, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment contains Chinese characters. For consistency and accessibility in an English codebase, comments should be written in English. Consider translating to "// In our definition, all CellValue types are atomic".

Suggested change
// 在我们的定义中,所有 CellValue 都是原子的
// In our definition, all CellValue types are atomic

Copilot uses AI. Check for mistakes.
match value with
| Null | Int _ | String _ | Bool _ | Float _ | Date _ -> true

let validate (relation: Relation) : Relation1NF option =
let allAtomic =
relation.Tuples
|> List.forall (fun tuple ->
tuple |> Map.forall (fun _ v -> isAtomic v)
)
if allAtomic then Some { Relation = relation }
else None

// 2NF: Second Normal Form
type Relation2NF = {
Relation1NF: Relation1NF
PrimaryKey: AttributeSet
FunctionalDependencies: FunctionalDependency list
// 没有部分依赖:所有非主属性完全依赖于候选键
Copy link

Copilot AI Dec 31, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment contains Chinese characters. For consistency and accessibility in an English codebase, comments should be written in English. Consider translating to "// No partial dependencies: all non-prime attributes fully depend on the candidate key".

Suggested change
// 没有部分依赖:所有非主属性完全依赖于候选键
// No partial dependencies: all non-prime attributes fully depend on the candidate key

Copilot uses AI. Check for mistakes.
}

module Relation2NF =
let isProperSubset (subset: AttributeSet) (superset: AttributeSet) =
Set.isSubset subset superset && subset <> superset

let hasPartialDependency (primaryKey: AttributeSet) (fd: FunctionalDependency) (nonPrimeAttrs: AttributeSet) =
// 检查是否存在部分依赖
// 即:fd.Left 是主键的真子集,且 fd.Right 包含非主属性
Comment on lines +97 to +98
Copy link

Copilot AI Dec 31, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comments contain Chinese characters. For consistency and accessibility in an English codebase, comments should be written in English. Consider translating to "// Check if there is a partial dependency" and "// i.e., fd.Left is a proper subset of the primary key, and fd.Right contains non-prime attributes".

Suggested change
// 检查是否存在部分依赖
// 即:fd.Left 是主键的真子集,且 fd.Right 包含非主属性
// Check if there is a partial dependency
// i.e., fd.Left is a proper subset of the primary key, and fd.Right contains non-prime attributes

Copilot uses AI. Check for mistakes.
isProperSubset fd.Left primaryKey &&
not (Set.isEmpty (Set.intersect fd.Right nonPrimeAttrs))

let validate (relation1nf: Relation1NF) (primaryKey: AttributeSet) (fds: FunctionalDependency list) =
let allAttrs = relation1nf.Relation.Attributes |> Set.ofList
let nonPrimeAttrs = Set.difference allAttrs primaryKey

let hasPartialDeps =
fds |> List.exists (fun fd ->
hasPartialDependency primaryKey fd nonPrimeAttrs
)

if not hasPartialDeps then
Some {
Relation1NF = relation1nf
PrimaryKey = primaryKey
FunctionalDependencies = fds
}
else None

// 3NF: Third Normal Form
type Relation3NF = {
Relation2NF: Relation2NF
CandidateKeys: AttributeSet list
// 没有传递依赖:非主属性不依赖于其他非主属性
Copy link

Copilot AI Dec 31, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment contains Chinese characters. For consistency and accessibility in an English codebase, comments should be written in English. Consider translating to "// No transitive dependencies: non-prime attributes do not depend on other non-prime attributes".

Suggested change
// 没有传递依赖:非主属性不依赖于其他非主属性
// No transitive dependencies: non-prime attributes do not depend on other non-prime attributes

Copilot uses AI. Check for mistakes.
}

module Relation3NF =
let isSuperkey (relation: Relation) (candidateKeys: AttributeSet list) (attrs: AttributeSet) =
candidateKeys |> List.exists (fun key -> Set.isSubset key attrs)

let isPrimeAttribute (candidateKeys: AttributeSet list) (attr: AttributeName) =
candidateKeys |> List.exists (fun key -> Set.contains attr key)

let violates3NF (candidateKeys: AttributeSet list) (fd: FunctionalDependency) (allAttrs: AttributeSet) =
// 违反3NF如果:
// 1. X 不是超键
// 2. Y 包含非主属性
Comment on lines +134 to +136
Copy link

Copilot AI Dec 31, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comments contain Chinese characters. For consistency and accessibility in an English codebase, comments should be written in English. Consider translating to "// Violates 3NF if:", "// 1. X is not a superkey", and "// 2. Y contains non-prime attributes".

Copilot uses AI. Check for mistakes.
let relation = { Name = ""; Attributes = Set.toList allAttrs; Tuples = [] }
let isSuper = isSuperkey relation candidateKeys fd.Left

if isSuper then false
else
// 检查 fd.Right 是否包含非主属性
Copy link

Copilot AI Dec 31, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment contains Chinese characters. For consistency and accessibility in an English codebase, comments should be written in English. Consider translating to "// Check if fd.Right contains non-prime attributes".

Suggested change
// 检查 fd.Right 是否包含非主属性
// Check if fd.Right contains non-prime attributes

Copilot uses AI. Check for mistakes.
fd.Right |> Set.exists (fun attr -> not (isPrimeAttribute candidateKeys attr))

let validate (relation2nf: Relation2NF) (candidateKeys: AttributeSet list) =
let allAttrs = relation2nf.Relation1NF.Relation.Attributes |> Set.ofList

let violations =
relation2nf.FunctionalDependencies
|> List.exists (fun fd -> violates3NF candidateKeys fd allAttrs)

if not violations then
Some {
Relation2NF = relation2nf
CandidateKeys = candidateKeys
}
else None

// BCNF: Boyce-Codd Normal Form
type RelationBCNF = {
Relation3NF: Relation3NF
// 更严格:对于每个非平凡函数依赖 X -> Y,X 必须是超键
Copy link

Copilot AI Dec 31, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment contains Chinese characters. For consistency and accessibility in an English codebase, comments should be written in English. Consider translating to "// Stricter: for every non-trivial functional dependency X -> Y, X must be a superkey".

Suggested change
// 更严格:对于每个非平凡函数依赖 X -> Y,X 必须是超键
// Stricter: for every non-trivial functional dependency X -> Y, X must be a superkey

Copilot uses AI. Check for mistakes.
}

module RelationBCNF =
let isTrivialDependency (fd: FunctionalDependency) =
Set.isSubset fd.Right fd.Left

let isSuperkey (relation: Relation) (candidateKeys: AttributeSet list) (attrs: AttributeSet) =
candidateKeys |> List.exists (fun key -> Set.isSubset key attrs)
Comment on lines +169 to +170
Copy link

Copilot AI Dec 31, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The isSuperkey function is duplicated in both Relation3NF and RelationBCNF modules with identical implementations. Consider extracting this to a shared utility module to improve maintainability and reduce code duplication.

Copilot uses AI. Check for mistakes.

let validate (relation3nf: Relation3NF) =
let relation = relation3nf.Relation2NF.Relation1NF.Relation
let candidateKeys = relation3nf.CandidateKeys

let allValid =
relation3nf.Relation2NF.FunctionalDependencies
|> List.forall (fun fd ->
isTrivialDependency fd ||
isSuperkey relation candidateKeys fd.Left
)

if allValid then
Some { Relation3NF = relation3nf }
else None

// 4NF: Fourth Normal Form
type Relation4NF = {
RelationBCNF: RelationBCNF
MultivaluedDependencies: MultivaluedDependency list
// 对于每个非平凡多值依赖 X ->-> Y,X 必须是超键
Copy link

Copilot AI Dec 31, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment contains Chinese characters. For consistency and accessibility in an English codebase, comments should be written in English. Consider translating to "// For every non-trivial multivalued dependency X ->-> Y, X must be a superkey".

Copilot uses AI. Check for mistakes.
}

module Relation4NF =
let isTrivialMVD (mvd: MultivaluedDependency) (allAttrs: AttributeSet) =
Set.isEmpty mvd.Right ||
Set.isSubset allAttrs (Set.union mvd.Left mvd.Right)

let validate (bcnf: RelationBCNF) (mvds: MultivaluedDependency list) =
let relation = bcnf.Relation3NF.Relation2NF.Relation1NF.Relation
let allAttrs = relation.Attributes |> Set.ofList
let candidateKeys = bcnf.Relation3NF.CandidateKeys

let allValid =
mvds |> List.forall (fun mvd ->
isTrivialMVD mvd allAttrs ||
RelationBCNF.isSuperkey relation candidateKeys mvd.Left
)

if allValid then
Some {
RelationBCNF = bcnf
MultivaluedDependencies = mvds
}
else None

// 5NF (PJNF): Fifth Normal Form / Project-Join Normal Form
type Relation5NF = {
Relation4NF: Relation4NF
JoinDependencies: JoinDependency list
// 每个连接依赖都由候选键所蕴含
Copy link

Copilot AI Dec 31, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment contains Chinese characters. For consistency and accessibility in an English codebase, comments should be written in English. Consider translating to "// Every join dependency is implied by candidate keys".

Copilot uses AI. Check for mistakes.
}

module Relation5NF =
let validate (r4nf: Relation4NF) (jds: JoinDependency list) =
// 简化验证:实际实现需要检查连接依赖是否由候选键蕴含
Copy link

Copilot AI Dec 31, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment contains Chinese characters. For consistency and accessibility in an English codebase, comments should be written in English. Consider translating to "// Simplified validation: actual implementation needs to check if join dependencies are implied by candidate keys".

Copilot uses AI. Check for mistakes.
Some {
Relation4NF = r4nf
JoinDependencies = jds
}
Comment on lines +225 to +230
Copy link

Copilot AI Dec 31, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Relation5NF.validate function always returns Some without performing any actual validation. This creates a placeholder implementation that could lead to incorrect validation results. The comment acknowledges this is simplified, but it means 5NF validation is not actually working. Consider either implementing proper join dependency validation or explicitly documenting this limitation in the type's documentation.

Copilot uses AI. Check for mistakes.

// 6NF: Sixth Normal Form
type Relation6NF = {
Relation5NF: Relation5NF
// 支持所有连接依赖(最终范式,完全分解)
Copy link

Copilot AI Dec 31, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment contains Chinese characters. For consistency and accessibility in an English codebase, comments should be written in English. Consider translating to "// Supports all join dependencies (final normal form, complete decomposition)".

Copilot uses AI. Check for mistakes.
}

Copy link

Copilot AI Dec 31, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Relation6NF type is defined but lacks a validation module and function, unlike the other normal forms (1NF-5NF). This inconsistency in the API design makes the type less useful. Consider adding a Relation6NF module with a validate function for consistency with the other normal forms.

Suggested change
module Relation6NF =
let validate (r5nf: Relation5NF) =
// 简化验证:在当前模型中,6NF 仅作为 5NF 的包装,不添加额外约束
Some {
Relation5NF = r5nf
}

Copilot uses AI. Check for mistakes.
// DKNF: Domain-Key Normal Form
type Constraint =
| DomainConstraint of AttributeName * Domain
| KeyConstraint of AttributeSet

type RelationDKNF = {
Relation: Relation
Constraints: Constraint list
// 所有约束都是域约束或键约束的逻辑结果
Copy link

Copilot AI Dec 31, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment contains Chinese characters. For consistency and accessibility in an English codebase, comments should be written in English. Consider translating to "// All constraints are logical consequences of domain constraints or key constraints".

Copilot uses AI. Check for mistakes.
}
Copy link

Copilot AI Dec 31, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The RelationDKNF type is defined but lacks a validation module and function, unlike the other normal forms. This inconsistency in the API design makes the type less useful. Consider adding a RelationDKNF module with a validate function for consistency with the other normal forms.

Suggested change
}
}
module RelationDKNF =
let validate (relation: Relation) (constraints: Constraint list) =
// 简化验证:实际实现需要检查所有约束是否为域约束或键约束的逻辑结果
Some {
Relation = relation
Constraints = constraints
}

Copilot uses AI. Check for mistakes.
Loading