我正在练习 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 魔法可用于定义“显示集”?
根据反馈更新:
在尝试了建议的两种解决方案并阅读
Haskell 中的 `data` 和 `newtype` 之间的差异之后
,似乎使用type
或newtype
给了我相同的“性能”(即,阅读上面的链接),但“newtype”给了我更强的类型安全性,例如,:我可以将任何Int -> Bool
函数传递给接受type Set = Int -> Bool
但必须Set'
在定义为时传递 a 的函数newtype Set' = Set' (Int -> Bool)
。
{-# 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}