【问题标题】:Haskell: how to define instance Show Set for type Set = Int -> BoolHaskell:如何为 Set = Int -> Bool 类型定义实例 Show Set
【发布时间】:2013-10-05 20:31:29
【问题描述】:

我正在练习 Martin Odersky 在 Scala 和 Haskell 中的“Scala 中的函数式编程原理”课程。 对于“集合为函数”的练习,我定义了一个“toString”函数:

import Data.List (intercalate)

type Set = Int -> Bool

contains :: Set -> Int -> Bool
contains s elem = s elem

bound = 1000

toString :: Set -> String
toString s =
    let xs = [(show x) | x <- [(-bound) .. bound], contains s x]
    in "{" ++ (intercalate "," xs) ++ "}"

-- toString (\x -> x > -3 && x < 10)
-- => "{-2,-1,0,1,2,3,4,5,6,7,8,9}"

如果能够定义就好了:

instance Show Set where
    show Set = ...

但定义需要引用和调用代表Set的函数thqt(即参见'toString'函数)。

是否有任何 Haskell 魔法可用于定义“显示集”?

根据反馈更新:

在尝试了建议的两种解决方案并阅读之后 Difference between `data` and `newtype` in Haskell 似乎使用typenewtype 给了我相同的“性能”(即,阅读上面的链接),但“新类型”给了我更强的类型安全性,例如:我可以将任何Int -&gt; Bool 函数传递给函数接受type Set = Int -&gt; Bool,但在定义为newtype Set' = Set' (Int -&gt; Bool) 时必须传递Set'

{-# LANGUAGE TypeSynonymInstances, FlexibleInstances #-}

import Data.List (intercalate)

bound = 1000

-- ALTERNATE #1

type Set = Int -> Bool

contains :: Set -> Int -> Bool
contains s elem = s elem

intersect :: Set -> Set -> Set
intersect s t = \x -> s x && t x

toString :: Set -> String
toString s =
    let xs = [(show x) | x <- [(-bound) .. bound], contains s x]
    in "{" ++ (intercalate "," xs) ++ "}"

instance Show Set where show = toString

-- ALTERNATE #2

newtype Set' = Set' (Int -> Bool)

contains' :: Set' -> Int -> Bool
contains' (Set' s) elem = s elem

intersect' :: Set' -> Set' -> Set'
intersect' (Set' s) (Set' t) = Set' (\x -> s x && t x)

instance Show Set' where
    show (Set' s) =
        let xs = [(show x) | x <- [(-bound) .. bound], s x]
        in "{" ++ (intercalate "," xs) ++ "}"

anyIntBoolFun1 = \x -> -10 < x
anyIntBoolFun2 = \x ->   x < 0
setIntBoolFun1 = Set' anyIntBoolFun1
setIntBoolFun2 = Set' anyIntBoolFun2

main = do
    putStrLn $ show $ intersect  anyIntBoolFun1 anyIntBoolFun2
    putStrLn $ show $ intersect' setIntBoolFun1 setIntBoolFun2

-- *Main> main
-- {-9,-8,-7,-6,-5,-4,-3,-2,-1}
-- {-9,-8,-7,-6,-5,-4,-3,-2,-1}

【问题讨论】:

    标签: haskell typeclass


    【解决方案1】:

    是的,就这么简单

    instance Show Set where show = toString
    

    虽然您需要打开 TypeSynonymInstancesFlexibleInstances。完整的文件如下所示:

    {-# LANGUAGE TypeSynonymInstances, FlexibleInstances #-}
    
    import Data.List (intercalate)
    
    type Set = Int -> Bool
    
    contains :: Set -> Int -> Bool
    contains s elem = s elem
    
    bound = 1000
    
    toString :: Set -> String
    toString s =
        let xs = [(show x) | x <- [(-bound) .. bound], contains s x]
        in "{" ++ (intercalate "," xs) ++ "}"
    
    instance Show Set where show = toString
    

    在 ghci 中:

    *Main> (\x -> x > -3 && x < 10) :: Set
    {-2,-1,0,1,2,3,4,5,6,7,8,9}
    

    但是,这有一些警告:即,多态函数不会匹配给定的实例。 (例如,上面的 ghci 示例中的类型归属 :: Set 是必需的。)

    【讨论】:

      【解决方案2】:

      您需要将Set 设为新类型而不是类型同义词,如下所示:

      newtype Set = Set { unSet :: Int -> Bool }
      

      然后你可以让它成为任何类的实例,比如Show:

      instance Show Set where
          show (Set s) =
              let xs = [(show x) | x <- [(-bound) .. bound], contains s x]
              in "{" ++ (intercalate "," xs) ++ "}"
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2013-09-27
        • 2022-11-30
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-09-14
        相关资源
        最近更新 更多