【问题标题】:How do I set default values in a record如何在记录中设置默认值
【发布时间】:2015-11-05 02:08:24
【问题描述】:

我正在尝试在可被覆盖的记录对象中设置默认值。

data Car c y = Car {
    company :: c,
    year :: y
    }

我想做的是设置一个默认值:

data Car c y = Car {
    company :: c -- OR "Ford"
    year :: y
    }

到目前为止,我已经尝试通过将 c 的类型设置为 Maybe 类型来做到这一点:

data Car = Car {
    company:: Maybe String
    year :: Maybe Int
    }

但是我得到了这个可预测的错误:

Fields of `Car' not initialised: year

具有讽刺意味的是,这正是我想要解决的问题。我想生成一个新记录,其中包含我没有设置的值已经初始化。我发现的一种方法是部分应用 Car 类型:

data Car c y = {
    company :: c,
    year :: y
    }

let ford = Car "Ford" 

-- This produces a function (y -> Car [Char] y)

但这会产生两个新问题:

  1. 如果我的数据类型有 100 多个字段类型,我将得到 100 个阶乘柯里化函数

  2. 我可以创建的部分应用函数取决于声明中变量的顺序。例如,您会注意到我无法生成 car1988 函数。

如何编写一个函数来创建具有默认值的记录?请帮忙。

【问题讨论】:

    标签: haskell record


    【解决方案1】:

    这就是 Haskell prefers to handle in a library 的那种东西,而不是破解一些硬连线的语言支持(这可能会导致各种问题,就像它在 C++ 中所做的那样)。

    import Data.Default
    
    instance Default Car where
      def = Car Nothing Nothing
              -- or whatever you want as the defaults
    
    ford :: Car
    ford = def { company = Just "Ford" }
    

    GHCi> 福特
    汽车 {company = Just "Ford", year = Nothing}

    您也可以只定义一个defaultCar,而不是使用Default 类。

    如果您的系统中尚未安装 data-default,您可能需要使用 cabal 来安装它。

    【讨论】:

    • 补充一点,"smart constructors"(这种结构)总是最好的方式。您可以使用任何您喜欢的参数来拥有任意数量的参数,从模块中导出一些而一些不导出,如果您的类型是多态的,您可以选择为您想要处理的每个更具体的类型使用不同的构造函数。
    • 非常好。但是你是什么意思“而不是使用Default 类”?要定义defaultCar,我需要使用这个Default 构造,对吗?
    • 不,您可以定义一个正常值defaultCar,然后在您需要非标准汽车时对其进行修改。另外,如果你想使用Default,那么你应该只使用data-default-class 包,因为它更轻量级
    • 我理解这个 defaultCar 类似于 let defaultCar c y = Car {company = Just c, year = Just y} 但这会产生与上面概述的相同的问题。
    • @dopatraman Nah,写defaultCar = Car Nothing Nothing。然后ford = defaultCar { company = Just "Ford" } 就像在答案中一样工作,但名称为defaultCar 而不是def。
    【解决方案2】:

    在使用 Data.Text 时,我会使用稍微冗长的方法。

    {-#Language OverloadedString#-}
    
    import Data.Text as T
    
    data Car c y = Car {
        company :: Text 
        year :: Double
        }
    
    toCar :: [T.Text] -> Car
    toCar inp = case inp of 
                  [] -> fail "Give me an input"
                  [v:h] -> Car { company = justifyRight 1 "Ford" h 
                               , year = read $ T.unpack $ last inp
                               }
    
    

    这将接受inp ["8"] 和inp ["Ashburn", "8"] 等输入

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-10-01
      • 2013-06-04
      • 1970-01-01
      • 2011-07-23
      • 2020-07-30
      • 2010-11-14
      • 2021-09-22
      • 2020-01-18
      相关资源
      最近更新 更多