Can any partial function be converted to a total version in Haskell?
Asked Answered
R

3

6

So far I have seen numerous "Maybe" versions of certain partial functions that would potentially result in ⊥, like readMaybe for read and listToMaybe for head; sometimes I wonder if we can generalise the idea and work out such a function safe :: (a -> b) -> (a -> Maybe b) to convert any partial function into their safer total alternative that returns Nothing on any instances where error stack would have been called in the original function. As till now I have not found a way to implement such safe function or existing implementations of a similar kind, and I come to doubt if this idea is truly viable.

Rosellaroselle answered 12/10, 2022 at 19:55 Comment(0)
C
6

There are two kinds of bottom actually, non-termination and error. You cannot catch non-termination, for obvious reasons, but you can catch errors. Here is a quickly thrown-together version (I am not an expert so there are probably better ways)

{-# LANGUAGE ScopedTypeVariables #-}

import Control.Exception
import System.IO.Unsafe

safe f = unsafePerformIO $ do
  z <- try (evaluate f)
  let r = case z of
     Left (e::SomeException) -> Nothing
     Right k -> Just k
  return r

Here are some examples

*Main > safe (head [42]) 
Just 42
*Main > safe (head []) 
Nothing
*Main λ safe (1 `div` 0)
Nothing
*Main λ safe (1 `div` 2)
Just 0
Cayla answered 12/10, 2022 at 21:4 Comment(1)
WIth safe you can define a pattern synonym: pattern Safe :: a -> a; pattern Safe a <- (safe -> Just a) where Safe a = a. Now you can pattern match and make sure it didn't throw an exception: f (Safe a) = .. this branch won't be called if the user inputs div 0 0Subclimax
P
6

No, it's not possible. It violates a property called "monotonicity", which says that a value cannot become more defined as you process it. You can't branch on bottoms - attempting to process one always results in bottom.

Or at least, that's all true of the domain theory Haskell evaluation is based on. But Haskell has a few extra features domain theory doesn't... Like executing IO actions being a different thing than evaluation, and unsafePerformIO letting you hide execution inside evaluation. The spoon library packages all of these ideas together as well as can be done. It's not perfect. It has holes, because this isn't something you're supposed to be able to do. But it does the job in a bunch of common cases.

Plutus answered 12/10, 2022 at 20:5 Comment(0)
C
6

There are two kinds of bottom actually, non-termination and error. You cannot catch non-termination, for obvious reasons, but you can catch errors. Here is a quickly thrown-together version (I am not an expert so there are probably better ways)

{-# LANGUAGE ScopedTypeVariables #-}

import Control.Exception
import System.IO.Unsafe

safe f = unsafePerformIO $ do
  z <- try (evaluate f)
  let r = case z of
     Left (e::SomeException) -> Nothing
     Right k -> Just k
  return r

Here are some examples

*Main > safe (head [42]) 
Just 42
*Main > safe (head []) 
Nothing
*Main λ safe (1 `div` 0)
Nothing
*Main λ safe (1 `div` 2)
Just 0
Cayla answered 12/10, 2022 at 21:4 Comment(1)
WIth safe you can define a pattern synonym: pattern Safe :: a -> a; pattern Safe a <- (safe -> Just a) where Safe a = a. Now you can pattern match and make sure it didn't throw an exception: f (Safe a) = .. this branch won't be called if the user inputs div 0 0Subclimax
E
4

Consider the function

collatz :: Integer -> ()
collatz 1 = ()
collatz n
 | even n     = collatz $ n`div`2
 | otherwise  = collatz $ 3*n + 1

(Let's pretend Integer is the type of positive whole numbers for simplicity)

Is this a total function? Nobody knows! For all we know, it could be total, so your proposed safe-guard can't ever yield Nothing. But neither has anybody found a proof that it is total, so if safe just always gives back Just (collatz n) then this may still be only partial.

Elston answered 12/10, 2022 at 20:27 Comment(1)
Of course you cannot catch bottoms like that, but you can catch Prelude::error and such, which is what OP seems to be asking about.Cayla

© 2022 - 2024 — McMap. All rights reserved.