Is it possible to define a function on a subset of an existing type?

后端 未结 5 1730
夕颜
夕颜 2021-01-18 04:40

I\'m new to Haskell and would like to know whether it\'s possible to define a function that is only defined on a subset of an already existing type, without actually having

相关标签:
5条回答
  • 2021-01-18 05:02

    No. The type system would need to support refinement types (or full dependent types, as suggested by @jozefg).

    Here is a Haskell extension with refinement types.

    http://goto.ucsd.edu/~rjhala/liquid/haskell/blog/blog/2013/01/01/refinement-types-101.lhs/

    0 讨论(0)
  • 2021-01-18 05:03

    One possibility would be

    newtype Even n = Even n
    getEven (Even n) = 2*n
    
    squared :: Num n => Even n -> Even n
    squared (Even n) = Even (2*n*n)
    
    0 讨论(0)
  • 2021-01-18 05:10

    In general no. Such a thing is called a subset type, it's a hallmark of dependent types which Haskell doesn't have. Usually it's implemented by boxing a value with a proof that the value satisfies some property, but since we have no notion of proofs in Haskell, we're stuck.

    Usually the way to fake it is with "smart constructors".

    newtype Even = Even {unEven :: Integer} deriving (Eq, Show, Ord)
    
    toEven :: Integer -> Maybe Even
    toEven a | even a = Just $ Even a
             | otherwise = Nothing
    

    And then hide the Even constructor.

    If you really really want it, you can switch to a language that can interop with Haskell that has dependent types (Coq and Agda spring to mind).

    0 讨论(0)
  • 2021-01-18 05:16

    Wrap the subset in a newtype

    newtype EvenInteger = EvenInteger {
        unEvenInteger :: Integer
    } deriving (Show, Eq, Ord, Num)
    
    mkEvenInteger :: Integer -> Maybe EvenInteger
    mkEvenInteger n = case n % 2 of
        0 -> Just $ EvenInteger n
        _ -> Nothing
    
    squared :: EvenInteger -> EvenInteger
    squared n = n * n
    
    0 讨论(0)
  • 2021-01-18 05:18

    As mentioned elsewhere, refinement types like in LiquidHaskell can express this. Here's what it looks like:

    module Evens where
    
    {-@ type Even = {v:Int | v mod 2 = 0} @-}
    
    {-@ square :: Even -> Int @-}
    square :: Int -> Int
    square n = n * n
    
    -- calling the function:
    yup = square 4
    -- nope = square 3 -- will not compile if this is uncommented
    

    You can try this out by plugging it in here: http://goto.ucsd.edu:8090/index.html

    0 讨论(0)
提交回复
热议问题