sanctuary

Wrong answer from S.min when strings used


S.min ('1') ('02') =>'02'

Why is this even possible? (yes type coercion... but this is Sanctuary) Can Sanctuary be configured so that Nothing is returned when Strings are used? Is there an elegant way to deal with this?


Solution

  • Let's consider the type of S.min:

    min :: Ord a => a -> a -> a
    

    String satisfies the requirements of Ord, so String -> String -> String is one possible specialization:

    > S.min ('foo') ('bar')
    'bar'
    

    If you are dealing with inputs that should be numbers but may not be, the best approach is to deal with the uncertainty up front:

    //    untrustedInput1 :: Any
    //    untrustedInput2 :: Any
    
    //    input1 :: Maybe Number
    const input1 = S.filter (S.is ($.Number)) (S.Just (untrustedInput1));
    
    //    input2 :: Maybe Number
    const input2 = S.filter (S.is ($.Number)) (S.Just (untrustedInput2));
    

    Then, you could use S.lift2 to transform S.min into a function that can operate on Maybe Number values:

    S.lift2 (S.min) :: (Apply f, Ord a) => f a -> f a -> f a
    

    The signature above can be specialized like so:

    S.lift2 (S.min) :: Maybe Number -> Maybe Number -> Maybe Number
    

    The final step is to apply S.lift2 (S.min) to the trusted inputs:

    S.lift2 (S.min) (input1) (input2)
    

    Here is a full working example:

    > S.lift2 (S.min)
    .         (S.filter (S.is ($.Number)) (S.Just ('1')))
    .         (S.filter (S.is ($.Number)) (S.Just ('02')))
    Nothing