向函数添加第二个参数

问题描述 投票:0回答:1

我想向下面给出的代码添加一个参数,来自这个线程

import Numeric.GSL.ODE
import Numeric.LinearAlgebra
import Numeric.AD

vanderpol :: Vector Double  -- ^ Time points
         -> [Vector Double]
vanderpol ts = toColumns $
         odeSolveV (BSimp $ \t -> fromLists . jac t . toList)
                   0.1 1e-8 1e-8
                   (\t -> fromList . xdot t . toList)
                   (fromList [0.5,0]) ts
 where xdot :: Num a => a -> [a] -> [a]
       xdot t [x,v] = [v, -x*(1-x^2)]
       jac :: Double -> [Double] -> [[Double]]
       jac t = jacobian (xdot $ realToFrac t)

但是,我似乎不知道该怎么做。我的想法是这样的,我们将

mu
传递给
xdot
,我认为这会导致需要将
mu
传递给
jac

import Numeric.GSL.ODE
import Numeric.LinearAlgebra
import Numeric.AD

vanderpol :: Vector Double  -- ^ Time points
         -> [Vector Double]
vanderpol ts = toColumns $
         odeSolveV (BSimp $ \t -> fromLists . jac t mu . toList)
                   0.1 1e-8 1e-8
                   (\t -> fromList . xdot t mu . toList)
                   (fromList [0.5,0]) ts
 where xdot :: Num a => a -> [a] -> [a]
       xdot t mu [x,v] = [v, -x*mu*(1-x^2)]
       jac :: Double -> [Double] -> [[Double]]
       jac t = jacobian (xdot $ realToFrac t mu)
       mu = 2 :: Double

如何编辑此代码以便将

Double
(Double, Double)
传递给
xdot
?这需要编辑
jac
吗?

haskell ode
1个回答
1
投票

根据 @leftroundabout 的评论,您不需要将

mu
设置为
xdot
jac
的参数,但在这里获取类型很棘手。如果你想将
mu
作为参数传递给
vanderpol
,秘密是
mu
需要有一个足够通用的类型,它可以用作
Double
(如
xdot
中所要求的)
odeSolveV
的第五个参数,作为
ReverseDouble s
ad
jacobian
函数所需的奇怪类型。

将其定义为一般多态类型是不够的:

vanderpol :: Num a => a     -- Not polymorphic enough!
          -> Vector Double
          -> [Vector Double]
vanderpol mu ts = ...

因为

vanderpol
的特定使用需要将
mu
专门化为特定的数字类型
a
,它可以是
Double
ReverseDouble s
,但不能同时是两者。相反,您需要更高级别的类型:

vanderpol :: (forall a. (Num a) => a)   -- rank 2 type
          -> Vector Double
          -> [Vector Double]
vanderpol mu ts = ...

然后就可以了。

出现以下内容则键入 check OK。请注意,

mu
仅作为
vanderpol
的参数出现,并在
xdot
内使用,就像普通的
mu
参数一样:

{-# LANGUAGE RankNTypes #-}

import Numeric.GSL.ODE
import Numeric.LinearAlgebra
import Numeric.AD.Mode.Reverse.Double

vanderpol :: (forall a. (Num a) => a)
         -> Vector Double  -- ^ Time points
         -> [Vector Double]
vanderpol mu ts = toColumns $
         odeSolveV (BSimp $ \t -> fromLists . jac t . toList)
                   0.1 1e-8 1e-8
                   (\t -> fromList . xdot t . toList)
                   (fromList [0.5,0]) ts
 where xdot t [x,v] = [v, -x*mu*(1-x^2)]
       jac t = jacobian (xdot t)

当你实际使用

vanderpol
时,你必须确保它的第一个参数“足够通用”。所以这有效:

main = print $ vanderpol 2 (fromList [1,2,3])

但这不是:

main = do
    mu <- readLn
    print $ vanderpol mu (fromList [1,2,3])

因为你不能

readLn
使用未指定类型的系数。

无论如何,看看您能做到什么程度,如果您在特定用例中设置

mu
时遇到困难,请发布后续问题。

© www.soinside.com 2019 - 2024. All rights reserved.