Haskell 有可能在哈斯克尔中推广方程吗?
为我对问题的拙劣措辞道歉。我试着寻找答案,但不知道该搜索什么,这使得我很难找到答案 这是一个计算三角形面积的简单函数Haskell 有可能在哈斯克尔中推广方程吗?,haskell,Haskell,为我对问题的拙劣措辞道歉。我试着寻找答案,但不知道该搜索什么,这使得我很难找到答案 这是一个计算三角形面积的简单函数 triangleArea :: Float -> Float -> Float -> Float triangleArea a b c | (a + b) <= c = error "Not a triangle!" | (a + c) <= b = error "Not a triangle!" | (b
triangleArea :: Float -> Float -> Float -> Float
triangleArea a b c
| (a + b) <= c = error "Not a triangle!"
| (a + c) <= b = error "Not a triangle!"
| (b + c) <= a = error "Not a triangle!"
| otherwise = sqrt (s * (s - a) * (s - b) * (s - c))
where s = (a + b + c) / 2
Haskell知道检查这三个参数的每个可能组合。我认为@behzad.nouri的评论是最好的。有时做一点数学是编程的最好方法。这里有一个关于@melpomene解决方案的有点夸张的扩展,我认为分享它会很有趣。让我们编写一个类似于置换的函数,但它计算组合:
import Control.Arrow (first, second)
-- choose n xs returns a list of tuples, the first component of each having
-- n elements and the second component having the rest, in all combinations
-- (ignoring order within the lists). N.B. this would be faster if implemented
-- using a DList.
choose :: Int -> [a] -> [([a],[a])]
choose 0 xs = [([], xs)]
choose _ [] = []
choose n (x:xs) =
map (first (x:)) (choose (n-1) xs) ++
map (second (x:)) (choose n xs)
所以
现在你可以写作了
triangleArea a b c
| or [ x + y <= z | ([x,y], [z]) <- choose 2 [a,b,c] ] = error ...
triangleareaa a b c
|或者[x+y这里有两个想法
使用现有工具,您可以生成参数的所有排列,并检查它们是否都满足条件。因此:
import Data.List
triangleArea a b c
| any (\[x, y, z] -> x + y <= z) (permutations [a,b,c])
= error "Not a triangle!"
| otherwise = {- ... -}
我们可以使用它构建一个只选择适当元素三元组的函数:
triples :: [a] -> [(a, a, a)]
triples xs = do
(b1, v1, e1) <- zippers xs
(b2, v2, e2) <- zippers e1
v3 <- b1 ++ b2 ++ e2
return (v1, v2, v3)
triples::[a]->[(a,a,a)]
三元组xs=do
(b1、v1、e1)这并没有解决如何缩短错误检查代码的问题,但您可以通过定义一些具有不变量的新类型来限制重复错误检查的频率。此函数需要进行错误检查,因为您不能信任用户提供构成合理三角形的Float
三元组,如果您继续定义fu这样,您编写的每个三角形相关函数都需要类似的错误检查
但是,如果定义三角形类型,则在创建三角形时只能检查一次不变量,然后所有其他函数将保证接收有效三角形:
module Triangle (Triangle(), mkTriangle, area) where
data Triangle a = Triangle a a a deriving Show
mkTriangle :: (Num a, Ord a) => a -> a -> a -> Either String (Triangle a)
mkTriangle a b c
| a + b <= c = wrong
| a + c <= b = wrong
| b + c <= a = wrong
| otherwise = Right $ Triangle a b c
where wrong = Left "Not a triangle!"
area :: Floating a => Triangle a -> a
area (Triangle a b c) = sqrt (s * (s - a) * (s - b) * (s - c))
where s = (a + b + c) / 2
模块三角形(Triangle(),mkTriangle,area),其中
数据三角形a=三角形a派生显示
mkTriangle::(numa,orda)=>a->a->a->任一字符串(三角形a)
三角形a b c
|a+b好吧,你可以写任何[arg1+arg2]你的3个条件相当于a+b+c@behzad.nouri你可以用它来发布一个答案
zippers :: [a] -> [([a], a, [a])]
zippers = go [] where
go b [] = []
go b (v:e) = (b, v, e) : go (v:b) e
triples :: [a] -> [(a, a, a)]
triples xs = do
(b1, v1, e1) <- zippers xs
(b2, v2, e2) <- zippers e1
v3 <- b1 ++ b2 ++ e2
return (v1, v2, v3)
triangleArea a b c
| any (\(x, y, z) -> x + y <= z) (triples [a,b,c])
= error "Not a triangle!"
| otherwise = {- ... -}
module Triangle (Triangle(), mkTriangle, area) where
data Triangle a = Triangle a a a deriving Show
mkTriangle :: (Num a, Ord a) => a -> a -> a -> Either String (Triangle a)
mkTriangle a b c
| a + b <= c = wrong
| a + c <= b = wrong
| b + c <= a = wrong
| otherwise = Right $ Triangle a b c
where wrong = Left "Not a triangle!"
area :: Floating a => Triangle a -> a
area (Triangle a b c) = sqrt (s * (s - a) * (s - b) * (s - c))
where s = (a + b + c) / 2