<commit_before>import Foundation

public struct FreeModule<_R: Ring>: Module, Hashable, CustomStringConvertible {
    public typealias R = _R
    
    public let name: String
    internal let dict: [String : R]
    
    public subscript(a: String) -> R {
        get {
            return dict[a] ?? 0
        }
    }
    
    public init(_ name: String) {
        self.name = name
        self.dict = [name: 1]
    }
    
    public init(_ dict: [String : R]) {
        self.name = ""
        self.dict = dict
    }
    
    public static var zero: FreeModule<R> {
        return FreeModule<R>.init([:])
    }
    
    public var bases: [String] {
        return Array(dict.keys)
    }
    
    public func coeff(_ name: String) -> R {
        return dict[name] ?? 0
    }
    
    public var hashValue: Int {
        return 0 // TODO
    }
    
    public var description: String {
        return dict.isEmpty ? "0" : Array(dict.keys).sorted().map({"\(coeff($0))\($0)"}).joined(separator: " + ")
    }
}

// Operations

public func ==<R: Ring>(a: FreeModule<R>, b: FreeModule<R>) -> Bool {
    return a.dict == b.dict
}

public func +<R: Ring>(a: FreeModule<R>, b: FreeModule<R>) -> FreeModule<R> {
    let keys = Set(a.dict.keys).union(Set(b.dict.keys))
    let dict = Dictionary.generateBy(keys: keys) {
        a[$0] + b[$0]
    }
    return FreeModule<R>(dict)
}<commit_msg>improve FreeModule description.<commit_after>import Foundation

public struct FreeModule<_R: Ring>: Module, Hashable, CustomStringConvertible {
    public typealias R = _R
    
    public let name: String
    internal let dict: [String : R]
    
    public subscript(a: String) -> R {
        get {
            return dict[a] ?? 0
        }
    }
    
    public init(_ name: String) {
        self.name = name
        self.dict = [name: 1]
    }
    
    public init(_ dict: [String : R]) {
        self.name = ""
        self.dict = dict
    }
    
    public static var zero: FreeModule<R> {
        return FreeModule<R>.init([:])
    }
    
    public var bases: [String] {
        return Array(dict.keys)
    }
    
    public func coeff(_ name: String) -> R {
        return dict[name] ?? 0
    }
    
    public var hashValue: Int {
        return 0 // TODO
    }
    
    public var description: String {
        return dict.isEmpty ? "0" :
            Array(dict.keys)
                .sorted()
                .map({coeff($0) == R.zero ? "" : "\(coeff($0))\($0)"})
                .filter({$0 != ""})
                .joined(separator: " + ")
    }
}

// Operations

public func ==<R: Ring>(a: FreeModule<R>, b: FreeModule<R>) -> Bool {
    return a.dict == b.dict
}

public func +<R: Ring>(a: FreeModule<R>, b: FreeModule<R>) -> FreeModule<R> {
    let keys = Set(a.dict.keys).union(Set(b.dict.keys))
    let dict = Dictionary.generateBy(keys: keys) {
        a[$0] + b[$0]
    }
    return FreeModule<R>(dict)
}
{'fraction_non_alphanumeric': 0.14782908339076498, 'fraction_numerical': 0.006891798759476223, 'mean_word_length': 1.938259109311741, 'pattern_counts': {'":': 0, '<': 25, '<?xml version=': 0, '>': 33, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6064275', 'n_tokens_mistral': 967, 'n_tokens_neox': 945, 'n_words': 238}