Using Haskell's types to replace assert statements or if checks in other languages

后端 未结 3 1980
执笔经年
执笔经年 2021-02-19 15:07

Sorry if the question is very elementary, I am still very new to Haskell. Lets say I have a function that can only work with two numbers that are in the golden ration (1.618), h

3条回答
  •  北海茫月
    2021-02-19 15:44

    You might want an ADT that can only be constructed with golden ratio numbers then write myfun to accept that data type.

    I've assumed Integer as a base type, but you could use others (ex: Double or Float) or even be polymorphic.

    1) Make the ADT

    module Golden (Gold, getGold, buildGold) where
    
    data Gold = G Integer Integer
    
    getGold :: Gold -> (Integer, Integer)
    getGold (G x y) = (x, y)
    
    buildGold :: Integer -> Integer -> Maybe Gold
    buildGold x y
        | isGolden x y = Just (G x y)
        | otherwise    = Nothing
    

    Notice this module exports the Gold type but not the constructor (namely, not G). So the only way to get a value of type Gold is with buildGold which performs a run-time check - but only one - so the values of Gold can be used and assumed to be a golden ratio by all the consumers without checking.

    2) Use the ADT to build myfun

    myfun :: Gold -> ???
    myfun g = expr
      where (x, y) = getGold g
    

    Now if you try to call myfun with a non-golden number (a value not of type Gold) then you will get a compile time error.

    Recap To build golden numbers buildGold function must be used, which forces the number to be checked.

    Notice what gets checked when! You have a compile time guarantee that myfun, and all other functions you want to use with Gold, are always provided golden ratios. The program input (from user, network, or where ever) still needs runtime checks and that's what buildGold provides; obviously there's never going to be a program that can promise the human won't type something undesirable.

    The alternatives given in the comments to your question are also worthy of consideration. An ADT is slightly heavy weight if all you need is a single function, myfun, that can fail then just have myfun :: (Integer, Integer) -> Maybe ???.

提交回复
热议问题